Xcos MVC: use ScicosID() instead of 0
[scilab.git] / scilab / modules / scicos / src / cpp / Model.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include <string>
17 #include <vector>
18 #include <utility>
19 #include <algorithm>
20
21 #include "Model.hxx"
22 #include "utilities.hxx"
23
24 #include "model/BaseObject.hxx"
25 #include "model/Annotation.hxx"
26 #include "model/Diagram.hxx"
27 #include "model/Block.hxx"
28 #include "model/Link.hxx"
29 #include "model/Port.hxx"
30
31 namespace org_scilab_modules_scicos
32 {
33
34 Model::Model() :
35     lastId(ScicosID()), has_looped(false), allObjects()
36 {
37     std::vector<int> datatypeDefault (3, 1);
38     datatypeDefault[0] = -1;
39     datatypes.push_back(new model::Datatype(datatypeDefault));
40 }
41
42 Model::~Model()
43 {
44     while (!datatypes.empty())
45     {
46         Model::erase(datatypes[0]);
47     }
48     datatypes.clear();
49 }
50
51 ScicosID Model::createObject(kind_t k)
52 {
53     /*
54      * Allocate the object per kind
55      */
56     model::BaseObject* o;
57     switch (k)
58     {
59         case ANNOTATION:
60             o = new model::Annotation();
61             break;
62         case DIAGRAM:
63             o = new model::Diagram();
64             break;
65         case BLOCK:
66             o = new model::Block();
67             break;
68         case LINK:
69             o = new model::Link();
70             break;
71         case PORT:
72             o = new model::Port();
73             break;
74         default:
75             return ScicosID();
76     }
77
78     /*
79      * Found the next unused id
80      */
81     lastId++;
82     if (lastId == ScicosID())
83     {
84         lastId++;
85         has_looped = true;
86     }
87
88     if (has_looped)
89     {
90         bool has_looped_twice = false;
91
92         // while key is found
93         for (objects_map_t::iterator iter = allObjects.find(lastId);
94                 iter != allObjects.end();
95                 iter = allObjects.find(lastId))
96         {
97             // try a valid ID
98             lastId++;
99             if (lastId == ScicosID())
100             {
101                 lastId++;
102
103                 // return the invalid value if the loop counter encounter 2 zeros.
104                 if (has_looped_twice)
105                 {
106                     return ScicosID();
107                 }
108                 else
109                 {
110                     has_looped_twice = true;
111                 }
112             }
113         }
114     }
115
116     /*
117      * Insert then return
118      */
119     allObjects.emplace(lastId, o);
120     o->id(lastId);
121     return lastId;
122 }
123
124 unsigned Model::referenceObject(const ScicosID uid)
125 {
126     objects_map_t::iterator iter = allObjects.find(uid);
127     if (iter == allObjects.end())
128     {
129         return 0;
130     }
131
132     ModelObject& modelObject = iter->second;
133     return ++(modelObject.m_refCounter);
134 }
135
136 unsigned& Model::referenceCount(ScicosID uid)
137 {
138     objects_map_t::iterator iter = allObjects.find(uid);
139     if (iter == allObjects.end())
140     {
141         throw std::string("key has not been found");
142     }
143
144     ModelObject& modelObject = iter->second;
145     return modelObject.m_refCounter;
146
147 }
148
149 void Model::deleteObject(ScicosID uid)
150 {
151     objects_map_t::iterator iter = allObjects.find(uid);
152     if (iter == allObjects.end())
153     {
154         throw std::string("key has not been found");
155     }
156
157     ModelObject& modelObject = iter->second;
158     if (modelObject.m_refCounter == 0)
159     {
160         model::BaseObject* o = modelObject.m_o;
161         allObjects.erase(iter);
162         delete o;
163     }
164     else
165     {
166         --(modelObject.m_refCounter);
167     }
168 }
169
170 kind_t Model::getKind(ScicosID uid) const
171 {
172     model::BaseObject* o = getObject(uid);
173     if (o != nullptr)
174     {
175         return o->kind();
176     }
177     else
178     {
179         // return the first kind, it will be always ignored as the object is no more valid
180         return ANNOTATION;
181     }
182 }
183
184 std::vector<ScicosID> Model::getAll(kind_t k) const
185 {
186     std::vector<ScicosID> all;
187
188     for (objects_map_t::const_iterator it = allObjects.begin(); it != allObjects.end(); ++it)
189     {
190         if (it->second.m_o->kind() == k)
191         {
192             all.push_back(it->second.m_o->id());
193         }
194     }
195
196     return all;
197 }
198
199 model::BaseObject* Model::getObject(ScicosID uid) const
200 {
201     objects_map_t::const_iterator iter = allObjects.find(uid);
202     if (iter == allObjects.end())
203     {
204         return nullptr;
205     }
206
207     return iter->second.m_o;
208 }
209
210 // datatypes being a vector of Datatype pointers, we need a dereferencing comparison operator to use std::lower_bound()
211 static bool isInferior(const model::Datatype* d1, const model::Datatype* d2)
212 {
213     return *d1 < *d2;
214 }
215
216 model::Datatype* Model::flyweight(const model::Datatype& d)
217 {
218     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), &d, isInferior);
219     if (iter != datatypes.end() && !(d < **iter)) // if d is found
220     {
221         (*iter)->m_refCount++;
222         return *iter;
223     }
224     else
225     {
226         return *datatypes.insert(iter, new model::Datatype(d));
227     }
228 }
229
230 void Model::erase(model::Datatype* d)
231 {
232     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), d, isInferior);
233     if (iter != datatypes.end() && !(*d < **iter)) // if d is found
234     {
235         (*iter)->m_refCount--;
236         if ((*iter)->m_refCount < 0)
237         {
238             delete *iter;
239             datatypes.erase(iter);
240         }
241     }
242 }
243
244 } /* namespace org_scilab_modules_scicos */