Scicos: fix some invalid access
[scilab.git] / scilab / modules / scicos / src / cpp / Controller.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  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #include <string>
14 #include <vector>
15 #include <map>
16 #include <utility>
17 #include <algorithm>
18 #include <iterator>
19
20 #include "utilities.hxx"
21
22 #define REF_DEBUG 0
23 #if REF_DEBUG
24 #include "scilabWrite.hxx"
25 #define REF_PRINT(uid, refCount) \
26         do { \
27         std::stringstream print; \
28         print << "referenceObject( " << uid << " ) : " << refCount << std::endl; \
29         scilabForcedWrite(print.str().data()); \
30         } while(0)
31 #define UNREF_PRINT(uid, count) \
32         do { \
33         std::stringstream print; \
34         print << "unreferenceObject( " << uid << " ) : " << refCount << std::endl; \
35         scilabForcedWrite(print.str().data()); \
36         } while(0)
37 #define CLONE_PRINT(uid, clone) \
38         do { \
39         std::stringstream print; \
40         print << "cloneObject( " << uid << " ) : " << clone << std::endl; \
41         scilabForcedWrite(print.str().data()); \
42         } while(0)
43 #else
44 #define REF_PRINT(uid, refCount)
45 #define UNREF_PRINT(uid, refCount)
46 #define CLONE_PRINT(uid, clone)
47 #endif
48
49 #include "Controller.hxx"
50
51 #include "LoggerView.hxx"
52
53 namespace org_scilab_modules_scicos
54 {
55
56 /*
57  * Implement SharedData methods
58  */
59 Controller::SharedData::SharedData() :
60     model(), allNamedViews(), allViews()
61 {
62 }
63
64 Controller::SharedData::~SharedData()
65 {
66     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
67     {
68         delete *iter;
69     }
70 }
71
72 Controller::SharedData Controller::m_instance;
73
74 View* Controller::register_view(const std::string& name, View* v)
75 {
76     m_instance.allNamedViews.push_back(name);
77     m_instance.allViews.push_back(v);
78     return v;
79 }
80
81 void Controller::unregister_view(View* v)
82 {
83     view_set_t::iterator it = std::find(m_instance.allViews.begin(), m_instance.allViews.end(), v);
84     if (it != m_instance.allViews.end())
85     {
86         size_t d = std::distance(m_instance.allViews.begin(), it);
87         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
88         m_instance.allViews.erase(m_instance.allViews.begin() + d);
89     }
90 }
91
92 View* Controller::unregister_view(const std::string& name)
93 {
94     View* view = nullptr;
95
96     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
97     if (it != m_instance.allNamedViews.end())
98     {
99         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
100         view = *(m_instance.allViews.begin() + d);
101         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
102         m_instance.allViews.erase(m_instance.allViews.begin() + d);
103     }
104
105     return view;
106 }
107
108 View* Controller::look_for_view(const std::string& name)
109 {
110     View* view = nullptr;
111
112     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
113     if (it != m_instance.allNamedViews.end())
114     {
115         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
116         view = *(m_instance.allViews.begin() + d);
117     }
118
119     return view;
120 }
121
122 Controller::Controller()
123 {
124 }
125
126 Controller::~Controller()
127 {
128 }
129
130 ScicosID Controller::createObject(kind_t k)
131 {
132     ScicosID uid = m_instance.model.createObject(k);
133
134     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
135     {
136         (*iter)->objectCreated(uid, k);
137     }
138
139     return uid;
140 }
141
142 unsigned Controller::referenceObject(const ScicosID uid) const
143 {
144     unsigned refCount = m_instance.model.referenceObject(uid);
145     REF_PRINT(uid, refCount);
146
147     auto o = getObject(uid);
148     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
149     {
150         (*iter)->objectReferenced(uid, o->kind(), refCount);
151     }
152
153     return refCount;
154 }
155
156 void Controller::deleteObject(ScicosID uid)
157 {
158     // if this object is the empty uid, ignore it : is is not stored in the model
159     if (uid == 0)
160     {
161         return;
162     }
163
164     auto initial = getObject(uid);
165     const kind_t k = initial->kind();
166
167     // if this object has been referenced somewhere else do not delete it but decrement the reference counter
168     unsigned& refCount = m_instance.model.referenceCount(uid);
169     if (refCount > 0)
170     {
171         --refCount;
172         UNREF_PRINT(uid, refCount);
173
174         for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
175         {
176             (*iter)->objectUnreferenced(uid, k, refCount);
177         }
178         return;
179     }
180
181     // We need to delete this object and cleanup all the referenced model object
182
183     // disconnect / remove references of weak connected objects and decrement the reference count of all strongly connected objects.
184     if (k == ANNOTATION)
185     {
186         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
187         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
188         // RELATED_TO is not referenced back
189     }
190     else if (k == BLOCK)
191     {
192         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
193         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
194
195         deleteVector(uid, k, INPUTS);
196         deleteVector(uid, k, OUTPUTS);
197         deleteVector(uid, k, EVENT_INPUTS);
198         deleteVector(uid, k, EVENT_OUTPUTS);
199
200         unlink(uid, k, CHILDREN, PARENT_BLOCK);
201         deleteVector(uid, k, CHILDREN);
202         // FIXME what about REFERENCED_PORT ?
203     }
204     else if (k == DIAGRAM)
205     {
206         unlink(uid, k, CHILDREN, PARENT_DIAGRAM);
207         deleteVector(uid, k, CHILDREN);
208     }
209     else if (k == LINK)
210     {
211         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
212         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
213
214         unlinkVector(uid, k, SOURCE_PORT, CONNECTED_SIGNALS);
215         unlinkVector(uid, k, DESTINATION_PORT, CONNECTED_SIGNALS);
216     }
217     else if (k == PORT)
218     {
219         unlinkVector(uid, k, SOURCE_BLOCK, INPUTS);
220         unlinkVector(uid, k, SOURCE_BLOCK, OUTPUTS);
221         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_INPUTS);
222         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_OUTPUTS);
223
224         unlink(uid, k, CONNECTED_SIGNALS, SOURCE_PORT);
225         unlink(uid, k, CONNECTED_SIGNALS, DESTINATION_PORT);
226     }
227
228     // delete the object
229     m_instance.model.deleteObject(uid);
230
231     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
232     {
233         (*iter)->objectDeleted(uid, k);
234     }
235 }
236
237 void Controller::unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
238 {
239     ScicosID v;
240     getObjectProperty(uid, k, uid_prop, v);
241     if (v != 0)
242     {
243         auto o = getObject(v);
244         if (o == nullptr)
245         {
246             return;
247         }
248
249         std::vector<ScicosID> children;
250         getObjectProperty(o->id(), o->kind(), ref_prop, children);
251
252         std::vector<ScicosID>::iterator it = std::find(children.begin(), children.end(), uid);
253         if (it != children.end())
254         {
255             children.erase(it);
256         }
257
258         setObjectProperty(o->id(), o->kind(), ref_prop, children);
259     }
260 }
261
262 void Controller::unlink(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
263 {
264     std::vector<ScicosID> v;
265     getObjectProperty(uid, k, uid_prop, v);
266     for (const ScicosID id : v)
267     {
268         if (id != 0)
269         {
270             auto o = getObject(id);
271             if (o == nullptr)
272             {
273                 continue;
274             }
275
276             // Find which end of the link is connected to the port
277             ScicosID oppositeRef;
278             getObjectProperty(o->id(), o->kind(), ref_prop, oppositeRef);
279             if (oppositeRef == uid)
280             {
281                 setObjectProperty(o->id(), o->kind(), ref_prop, ScicosID());
282             }
283         }
284     }
285 }
286
287 void Controller::deleteVector(ScicosID uid, kind_t k, object_properties_t uid_prop)
288 {
289     std::vector<ScicosID> children;
290     getObjectProperty(uid, k, uid_prop, children);
291
292     for (ScicosID id : children)
293     {
294         deleteObject(id);
295     }
296 }
297
298 ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren)
299 {
300     auto initial = getObject(uid);
301     const kind_t k = initial->kind();
302     ScicosID o = createObject(k);
303     mapped.insert(std::make_pair(uid, o));
304
305     // Get then set all properties per type that do not manage ScicosID
306     cloneProperties<double>(initial, o);
307     cloneProperties<int>(initial, o);
308     cloneProperties<bool>(initial, o);
309     cloneProperties<std::string>(initial, o);
310     cloneProperties<std::vector<double> >(initial, o);
311     cloneProperties<std::vector<int> >(initial, o);
312     cloneProperties<std::vector<std::string> >(initial, o);
313
314     // deep copy children, manage ScicosID and std::vector<ScicosID>
315     if (k == ANNOTATION)
316     {
317         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
318         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
319         deepClone(mapped, uid, o, k, RELATED_TO, true);
320     }
321     else if (k == BLOCK)
322     {
323         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
324         deepCloneVector(mapped, uid, o, k, INPUTS, true);
325         deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
326         deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
327         deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
328
329         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
330         if (cloneChildren)
331         {
332             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
333         }
334         // FIXME what about REFERENCED_PORT ?
335     }
336     else if (k == DIAGRAM)
337     {
338         if (cloneChildren)
339         {
340             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
341         }
342     }
343     else if (k == LINK)
344     {
345         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
346         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
347         deepClone(mapped, uid, o, k, SOURCE_PORT, false);
348         deepClone(mapped, uid, o, k, DESTINATION_PORT, false);
349     }
350     else if (k == PORT)
351     {
352         deepClone(mapped, uid, o, k, SOURCE_BLOCK, false);
353         deepCloneVector(mapped, uid, o, k, CONNECTED_SIGNALS, false);
354     }
355
356     return o;
357 }
358
359 void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
360 {
361     ScicosID v;
362     getObjectProperty(uid, k, p, v);
363
364     ScicosID cloned = 0;
365
366     std::map<ScicosID, ScicosID>::iterator it = mapped.find(v);
367     if (it != mapped.end())
368     {
369         cloned = it->second;
370     }
371     else
372     {
373         if (cloneIfNotFound)
374         {
375             if (v != 0)
376             {
377                 cloned = cloneObject(mapped, v, true);
378             }
379             else
380             {
381                 cloned = 0;
382             }
383         }
384         else
385         {
386             cloned = 0;
387         }
388     }
389
390     setObjectProperty(clone, k, p, cloned);
391 }
392
393 void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
394 {
395     std::vector<ScicosID> v;
396     getObjectProperty(uid, k, p, v);
397
398     std::vector<ScicosID> cloned;
399     cloned.reserve(v.size());
400
401     for (const ScicosID & id : v)
402     {
403         if (id == 0)
404         {
405             // Deleted Block, the cloning is done at Adapter level
406             cloned.push_back(id);
407             continue;
408         }
409
410         std::map<ScicosID, ScicosID>::iterator it = mapped.find(id);
411         if (it != mapped.end())
412         {
413             cloned.push_back(it->second);
414         }
415         else
416         {
417             if (cloneIfNotFound)
418             {
419                 if (id != 0)
420                 {
421                     cloned.push_back(cloneObject(mapped, id, true));
422                 }
423                 else
424                 {
425                     cloned.push_back(ScicosID());
426                 }
427             }
428             else
429             {
430                 cloned.push_back(ScicosID());
431             }
432         }
433     }
434
435     setObjectProperty(clone, k, p, cloned);
436 }
437
438 ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren)
439 {
440     std::map<ScicosID, ScicosID> mapped;
441     ScicosID clone = cloneObject(mapped, uid, cloneChildren);
442     CLONE_PRINT(uid, clone);
443     return clone;
444 }
445
446 kind_t Controller::getKind(ScicosID uid) const
447 {
448     return m_instance.model.getKind(uid);
449 }
450
451 std::vector<ScicosID> Controller::getAll(kind_t k) const
452 {
453     return m_instance.model.getAll(k);
454 }
455
456 model::BaseObject* Controller::getObject(ScicosID uid) const
457 {
458     return m_instance.model.getObject(uid);
459 }
460
461 } /* namespace org_scilab_modules_scicos */