Scicos: fix some issues detected by clang-analyzer
[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 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                     delete o;
107                     return ScicosID();
108                 }
109                 else
110                 {
111                     has_looped_twice = true;
112                 }
113             }
114         }
115     }
116
117     /*
118      * Insert then return
119      */
120     allObjects.emplace(lastId, o);
121     o->id(lastId);
122     return lastId;
123 }
124
125 unsigned Model::referenceObject(const ScicosID uid)
126 {
127     objects_map_t::iterator iter = allObjects.find(uid);
128     if (iter == allObjects.end())
129     {
130         return 0;
131     }
132
133     model::BaseObject* modelObject = iter->second;
134     return ++modelObject->refCount();
135 }
136
137 unsigned& Model::referenceCount(ScicosID uid)
138 {
139     objects_map_t::iterator iter = allObjects.find(uid);
140     if (iter == allObjects.end())
141     {
142         throw std::string("key has not been found");
143     }
144
145     model::BaseObject* modelObject = iter->second;
146     return modelObject->refCount();
147
148 }
149
150 void Model::deleteObject(ScicosID uid)
151 {
152     objects_map_t::iterator iter = allObjects.find(uid);
153     if (iter == allObjects.end())
154     {
155         throw std::string("key has not been found");
156     }
157
158     model::BaseObject* modelObject = iter->second;
159     if (modelObject->refCount() == 0)
160     {
161         allObjects.erase(iter);
162         delete modelObject;
163     }
164     else
165     {
166         --modelObject->refCount();
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->kind() == k)
191         {
192             all.push_back(it->second->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;
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 */