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