2bab7876681c225e43c42eb37a1bd569b86c1d51
[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 model::BaseObject* 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 nullptr;
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 (allobjects_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 nullptr;
134                 }
135                 else
136                 {
137                     has_looped_twice = true;
138                 }
139             }
140         }
141     }
142
143     /*
144      * Insert then return
145      */
146     o->id(lastId);
147     allObjects.emplace(lastId, o);
148     return o;
149 }
150
151 unsigned Model::referenceObject(model::BaseObject* object)
152 {
153     return ++object->refCount();
154 }
155
156 unsigned& Model::referenceCount(model::BaseObject* object)
157 {
158     return object->refCount();
159 }
160
161 void Model::deleteObject(model::BaseObject* object)
162 {
163     if (object->refCount() == 0)
164     {
165         allObjects.erase(object->id());
166         deleteBaseObject(object);
167     }
168     else
169     {
170         --object->refCount();
171     }
172 }
173
174 kind_t Model::getKind(ScicosID uid) const
175 {
176     model::BaseObject* o = getObject(uid);
177     if (o != nullptr)
178     {
179         return o->kind();
180     }
181     else
182     {
183         // return the first kind, it will be always ignored as the object is no more valid
184         return ANNOTATION;
185     }
186 }
187
188 std::vector<model::BaseObject*> Model::getAll(kind_t k) const
189 {
190     std::vector<model::BaseObject*> all;
191     for (auto it : allObjects)
192         if (it.second->kind() == k)
193         {
194             all.emplace_back(it.second);
195         }
196
197     return all;
198 }
199
200 model::BaseObject* Model::getObject(ScicosID uid) const
201 {
202     allobjects_t::const_iterator iter = allObjects.find(uid);
203     if (iter == allObjects.end())
204     {
205         return nullptr;
206     }
207
208     return iter->second;
209 }
210
211 // datatypes being a vector of Datatype pointers, we need a dereferencing comparison operator to use std::lower_bound()
212 static bool isInferior(const model::Datatype* d1, const model::Datatype* d2)
213 {
214     return *d1 < *d2;
215 }
216
217 model::Datatype* Model::flyweight(const model::Datatype& d)
218 {
219     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), &d, isInferior);
220     if (iter != datatypes.end() && !(d < **iter)) // if d is found
221     {
222         (*iter)->m_refCount++;
223         return *iter;
224     }
225     else
226     {
227         return *datatypes.insert(iter, new model::Datatype(d));
228     }
229 }
230
231 void Model::erase(model::Datatype* d)
232 {
233     datatypes_set_t::iterator iter = std::lower_bound(datatypes.begin(), datatypes.end(), d, isInferior);
234     if (iter != datatypes.end() && !(*d < **iter)) // if d is found
235     {
236         (*iter)->m_refCount--;
237         if ((*iter)->m_refCount < 0)
238         {
239             delete *iter;
240             datatypes.erase(iter);
241         }
242     }
243 }
244
245 } /* namespace org_scilab_modules_scicos */