CID 1321282: virtual destructors are not needed
[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-2017 - 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 /* define a custom delete as the BaseObject class is fully abstract */
52 static inline void deleteBaseObject(model::BaseObject* o)
53 {
54     switch (o->kind())
55     {
56         case ANNOTATION:
57             delete static_cast<model::Annotation*>(o);
58             break;
59         case DIAGRAM:
60             delete static_cast<model::Diagram*>(o);
61             break;
62         case BLOCK:
63             delete static_cast<model::Block*>(o);
64             break;
65         case LINK:
66             delete static_cast<model::Link*>(o);
67             break;
68         case PORT:
69             delete static_cast<model::Port*>(o);
70             break;
71         default:
72             break;
73     }
74 };
75
76
77 ScicosID Model::createObject(kind_t k)
78 {
79     /*
80      * Allocate the object per kind
81      */
82     model::BaseObject* o;
83     switch (k)
84     {
85         case ANNOTATION:
86             o = new model::Annotation();
87             break;
88         case DIAGRAM:
89             o = new model::Diagram();
90             break;
91         case BLOCK:
92             o = new model::Block();
93             break;
94         case LINK:
95             o = new model::Link();
96             break;
97         case PORT:
98             o = new model::Port();
99             break;
100         default:
101             return ScicosID();
102     }
103
104     /*
105      * Found the next unused id
106      */
107     lastId++;
108     if (lastId == ScicosID())
109     {
110         lastId++;
111         has_looped = true;
112     }
113
114     if (has_looped)
115     {
116         bool has_looped_twice = false;
117
118         // while key is found
119         for (objects_map_t::iterator iter = allObjects.find(lastId);
120                 iter != allObjects.end();
121                 iter = allObjects.find(lastId))
122         {
123             // try a valid ID
124             lastId++;
125             if (lastId == ScicosID())
126             {
127                 lastId++;
128
129                 // return the invalid value if the loop counter encounter 2 zeros.
130                 if (has_looped_twice)
131                 {
132                     deleteBaseObject(o);
133                     return ScicosID();
134                 }
135                 else
136                 {
137                     has_looped_twice = true;
138                 }
139             }
140         }
141     }
142
143     /*
144      * Insert then return
145      */
146     allObjects.emplace(lastId, o);
147     o->id(lastId);
148     return lastId;
149 }
150
151 unsigned Model::referenceObject(const ScicosID uid)
152 {
153     objects_map_t::iterator iter = allObjects.find(uid);
154     if (iter == allObjects.end())
155     {
156         return 0;
157     }
158
159     model::BaseObject* modelObject = iter->second;
160     return ++modelObject->refCount();
161 }
162
163 unsigned& Model::referenceCount(ScicosID uid)
164 {
165     objects_map_t::iterator iter = allObjects.find(uid);
166     if (iter == allObjects.end())
167     {
168         throw std::string("key has not been found");
169     }
170
171     model::BaseObject* modelObject = iter->second;
172     return modelObject->refCount();
173
174 }
175
176 void Model::deleteObject(ScicosID uid)
177 {
178     objects_map_t::iterator iter = allObjects.find(uid);
179     if (iter == allObjects.end())
180     {
181         throw std::string("key has not been found");
182     }
183
184     model::BaseObject* modelObject = iter->second;
185     if (modelObject->refCount() == 0)
186     {
187         allObjects.erase(iter);
188         deleteBaseObject(modelObject);
189     }
190     else
191     {
192         --modelObject->refCount();
193     }
194 }
195
196 kind_t Model::getKind(ScicosID uid) const
197 {
198     model::BaseObject* o = getObject(uid);
199     if (o != nullptr)
200     {
201         return o->kind();
202     }
203     else
204     {
205         // return the first kind, it will be always ignored as the object is no more valid
206         return ANNOTATION;
207     }
208 }
209
210 std::vector<ScicosID> Model::getAll(kind_t k) const
211 {
212     std::vector<ScicosID> all;
213
214     for (objects_map_t::const_iterator it = allObjects.begin(); it != allObjects.end(); ++it)
215     {
216         if (it->second->kind() == k)
217         {
218             all.push_back(it->second->id());
219         }
220     }
221
222     return all;
223 }
224
225 model::BaseObject* Model::getObject(ScicosID uid) const
226 {
227     objects_map_t::const_iterator iter = allObjects.find(uid);
228     if (iter == allObjects.end())
229     {
230         return nullptr;
231     }
232
233     return iter->second;
234 }
235
236 // datatypes being a vector of Datatype pointers, we need a dereferencing comparison operator to use std::lower_bound()
237 static bool isInferior(const model::Datatype* d1, const model::Datatype* d2)
238 {
239     return *d1 < *d2;
240 }
241
242 model::Datatype* Model::flyweight(const model::Datatype& d)
243 {
244     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), &d, isInferior);
245     if (iter != datatypes.end() && !(d < **iter)) // if d is found
246     {
247         (*iter)->m_refCount++;
248         return *iter;
249     }
250     else
251     {
252         return *datatypes.insert(iter, new model::Datatype(d));
253     }
254 }
255
256 void Model::erase(model::Datatype* d)
257 {
258     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), d, isInferior);
259     if (iter != datatypes.end() && !(*d < **iter)) // if d is found
260     {
261         (*iter)->m_refCount--;
262         if ((*iter)->m_refCount < 0)
263         {
264             delete *iter;
265             datatypes.erase(iter);
266         }
267     }
268 }
269
270 } /* namespace org_scilab_modules_scicos */