GPL + CeCILL Header change
[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  * 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 <atomic>
18 #include <string>
19 #include <vector>
20 #include <map>
21 #include <utility>
22 #include <algorithm>
23 #include <iterator>
24
25 #include "utilities.hxx"
26
27 #define REF_DEBUG 0
28 #if REF_DEBUG
29 #include "scilabWrite.hxx"
30 #define REF_PRINT(uid, refCount) \
31         do { \
32         std::stringstream print; \
33         print << "referenceObject( " << uid << " ) : " << refCount << std::endl; \
34         scilabForcedWrite(print.str().data()); \
35         } while(0)
36 #define UNREF_PRINT(uid, count) \
37         do { \
38         std::stringstream print; \
39         print << "unreferenceObject( " << uid << " ) : " << refCount << std::endl; \
40         scilabForcedWrite(print.str().data()); \
41         } while(0)
42 #define CLONE_PRINT(uid, clone) \
43         do { \
44         std::stringstream print; \
45         print << "cloneObject( " << uid << " ) : " << clone << std::endl; \
46         scilabForcedWrite(print.str().data()); \
47         } while(0)
48 #else
49 #define REF_PRINT(uid, refCount)
50 #define UNREF_PRINT(uid, refCount)
51 #define CLONE_PRINT(uid, clone)
52 #endif
53
54 #include "Controller.hxx"
55 #include "model/BaseObject.hxx"
56
57 #include "LoggerView.hxx"
58
59 namespace org_scilab_modules_scicos
60 {
61
62 static inline void lock(std::atomic_flag* m)
63 {
64     while (m->test_and_set(std::memory_order_acquire))  // acquire lock
65         ; // spin
66 }
67
68 static inline void unlock(std::atomic_flag* m)
69 {
70     m->clear(std::memory_order_release);
71 }
72
73 /*
74  * Implement SharedData methods
75  */
76 Controller::SharedData::SharedData() :
77     onModelStructuralModification(), model(),
78     onViewsStructuralModification(), allNamedViews(), allViews()
79 {
80     unlock(&onModelStructuralModification);
81     unlock(&onViewsStructuralModification);
82 }
83
84 Controller::SharedData::~SharedData()
85 {
86     lock(&onViewsStructuralModification);
87     for (view_set_t::iterator iter = allViews.begin(); iter != allViews.end(); ++iter)
88     {
89         delete *iter;
90     }
91     unlock(&onViewsStructuralModification);
92 }
93
94 Controller::SharedData Controller::m_instance;
95
96 View* Controller::register_view(const std::string& name, View* v)
97 {
98     lock(&m_instance.onViewsStructuralModification);
99
100     m_instance.allNamedViews.push_back(name);
101     m_instance.allViews.push_back(v);
102
103     unlock(&m_instance.onViewsStructuralModification);
104     return v;
105 }
106
107 void Controller::unregister_view(View* v)
108 {
109     lock(&m_instance.onViewsStructuralModification);
110
111     view_set_t::iterator it = std::find(m_instance.allViews.begin(), m_instance.allViews.end(), v);
112     if (it != m_instance.allViews.end())
113     {
114         size_t d = std::distance(m_instance.allViews.begin(), it);
115         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
116         m_instance.allViews.erase(m_instance.allViews.begin() + d);
117     }
118
119     unlock(&m_instance.onViewsStructuralModification);
120 }
121
122 View* Controller::unregister_view(const std::string& name)
123 {
124     View* view = nullptr;
125
126     lock(&m_instance.onViewsStructuralModification);
127
128     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
129     if (it != m_instance.allNamedViews.end())
130     {
131         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
132         view = *(m_instance.allViews.begin() + d);
133         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
134         m_instance.allViews.erase(m_instance.allViews.begin() + d);
135     }
136     unlock(&m_instance.onViewsStructuralModification);
137
138     return view;
139 }
140
141 View* Controller::look_for_view(const std::string& name)
142 {
143     View* view = nullptr;
144
145     lock(&m_instance.onViewsStructuralModification);
146     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
147     if (it != m_instance.allNamedViews.end())
148     {
149         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
150         view = *(m_instance.allViews.begin() + d);
151     }
152     unlock(&m_instance.onViewsStructuralModification);
153
154     return view;
155 }
156
157 Controller::Controller()
158 {
159 }
160
161 Controller::~Controller()
162 {
163 }
164
165 ScicosID Controller::createObject(kind_t k)
166 {
167     lock(&m_instance.onModelStructuralModification);
168     ScicosID uid = m_instance.model.createObject(k);
169     unlock(&m_instance.onModelStructuralModification);
170
171     lock(&m_instance.onViewsStructuralModification);
172     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
173     {
174         (*iter)->objectCreated(uid, k);
175     }
176     unlock(&m_instance.onViewsStructuralModification);
177
178     return uid;
179 }
180
181 unsigned Controller::referenceObject(const ScicosID uid) const
182 {
183     lock(&m_instance.onModelStructuralModification);
184
185     unsigned refCount = m_instance.model.referenceObject(uid);
186     REF_PRINT(uid, refCount);
187
188     auto o = m_instance.model.getObject(uid);
189     unlock(&m_instance.onModelStructuralModification);
190
191     lock(&m_instance.onViewsStructuralModification);
192     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
193     {
194         (*iter)->objectReferenced(uid, o->kind(), refCount);
195     }
196     unlock(&m_instance.onViewsStructuralModification);
197
198     return refCount;
199 }
200
201 void Controller::deleteObject(ScicosID uid)
202 {
203     // if this object is the empty uid, ignore it : is is not stored in the model
204     if (uid == 0)
205     {
206         return;
207     }
208
209     lock(&m_instance.onModelStructuralModification);
210
211     auto initial = m_instance.model.getObject(uid);
212     if (initial == nullptr)
213     {
214         // defensive programming
215         return;
216     }
217     const kind_t k = initial->kind();
218
219     // if this object has been referenced somewhere else do not delete it but decrement the reference counter
220     unsigned& refCount = m_instance.model.referenceCount(uid);
221     unlock(&m_instance.onModelStructuralModification);
222     if (refCount > 0)
223     {
224         --refCount;
225         UNREF_PRINT(uid, refCount);
226
227         lock(&m_instance.onViewsStructuralModification);
228         for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
229         {
230             (*iter)->objectUnreferenced(uid, k, refCount);
231         }
232         unlock(&m_instance.onViewsStructuralModification);
233         return;
234     }
235
236     // We need to delete this object and cleanup all the referenced model object
237
238     // disconnect / remove references of weak connected objects and decrement the reference count of all strongly connected objects.
239     if (k == ANNOTATION)
240     {
241         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
242         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
243         // RELATED_TO is not referenced back
244     }
245     else if (k == BLOCK)
246     {
247         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
248         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
249
250         deleteVector(uid, k, INPUTS);
251         deleteVector(uid, k, OUTPUTS);
252         deleteVector(uid, k, EVENT_INPUTS);
253         deleteVector(uid, k, EVENT_OUTPUTS);
254
255         unlink(uid, k, CHILDREN, PARENT_BLOCK);
256         deleteVector(uid, k, CHILDREN);
257         // FIXME what about REFERENCED_PORT ?
258     }
259     else if (k == DIAGRAM)
260     {
261         unlink(uid, k, CHILDREN, PARENT_DIAGRAM);
262         deleteVector(uid, k, CHILDREN);
263     }
264     else if (k == LINK)
265     {
266         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
267         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
268
269         unlinkVector(uid, k, SOURCE_PORT, CONNECTED_SIGNALS);
270         unlinkVector(uid, k, DESTINATION_PORT, CONNECTED_SIGNALS);
271     }
272     else if (k == PORT)
273     {
274         unlinkVector(uid, k, SOURCE_BLOCK, INPUTS);
275         unlinkVector(uid, k, SOURCE_BLOCK, OUTPUTS);
276         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_INPUTS);
277         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_OUTPUTS);
278
279         unlink(uid, k, CONNECTED_SIGNALS, SOURCE_PORT);
280         unlink(uid, k, CONNECTED_SIGNALS, DESTINATION_PORT);
281     }
282
283     // delete the object
284     lock(&m_instance.onModelStructuralModification);
285     m_instance.model.deleteObject(uid);
286     unlock(&m_instance.onModelStructuralModification);
287
288     lock(&m_instance.onViewsStructuralModification);
289     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
290     {
291         (*iter)->objectDeleted(uid, k);
292     }
293     unlock(&m_instance.onViewsStructuralModification);
294 }
295
296 void Controller::unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
297 {
298     ScicosID v;
299     getObjectProperty(uid, k, uid_prop, v);
300     if (v != 0)
301     {
302         auto o = getObject(v);
303         if (o == nullptr)
304         {
305             return;
306         }
307
308         std::vector<ScicosID> children;
309         getObjectProperty(o->id(), o->kind(), ref_prop, children);
310
311         std::vector<ScicosID>::iterator it = std::find(children.begin(), children.end(), uid);
312         if (it != children.end())
313         {
314             children.erase(it);
315         }
316
317         setObjectProperty(o->id(), o->kind(), ref_prop, children);
318     }
319 }
320
321 void Controller::unlink(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
322 {
323     std::vector<ScicosID> v;
324     getObjectProperty(uid, k, uid_prop, v);
325     for (const ScicosID id : v)
326     {
327         if (id != 0)
328         {
329             auto o = getObject(id);
330             if (o == nullptr)
331             {
332                 continue;
333             }
334
335             // Find which end of the link is connected to the port
336             ScicosID oppositeRef;
337             getObjectProperty(o->id(), o->kind(), ref_prop, oppositeRef);
338             if (oppositeRef == uid)
339             {
340                 setObjectProperty(o->id(), o->kind(), ref_prop, ScicosID());
341             }
342         }
343     }
344 }
345
346 void Controller::deleteVector(ScicosID uid, kind_t k, object_properties_t uid_prop)
347 {
348     std::vector<ScicosID> children;
349     getObjectProperty(uid, k, uid_prop, children);
350
351     for (ScicosID id : children)
352     {
353         deleteObject(id);
354     }
355 }
356
357 template<typename T>
358 void Controller::cloneProperties(model::BaseObject* initial, ScicosID clone)
359 {
360     for (int i = 0; i < MAX_OBJECT_PROPERTIES; ++i)
361     {
362         enum object_properties_t p = static_cast<enum object_properties_t>(i);
363
364         T value;
365         bool status = getObjectProperty(initial->id(), initial->kind(), p, value);
366         if (status)
367         {
368             setObjectProperty(clone, initial->kind(), p, value);
369         }
370     }
371 }
372
373 ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren, bool clonePorts)
374 {
375     auto initial = getObject(uid);
376     const kind_t k = initial->kind();
377     ScicosID o = createObject(k);
378     mapped.insert(std::make_pair(uid, o));
379
380     // Get then set all properties per type that do not manage ScicosID
381     cloneProperties<double>(initial, o);
382     cloneProperties<int>(initial, o);
383     cloneProperties<bool>(initial, o);
384     cloneProperties<std::string>(initial, o);
385     cloneProperties<std::vector<double> >(initial, o);
386     cloneProperties<std::vector<int> >(initial, o);
387     cloneProperties<std::vector<std::string> >(initial, o);
388
389     // deep copy children, manage ScicosID and std::vector<ScicosID>
390     if (k == ANNOTATION)
391     {
392         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
393         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
394         deepClone(mapped, uid, o, k, RELATED_TO, true);
395     }
396     else if (k == BLOCK)
397     {
398         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
399         if (clonePorts)
400         {
401             // Only copy the block, without any port
402             deepCloneVector(mapped, uid, o, k, INPUTS, true);
403             deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
404             deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
405             deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
406         }
407
408         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
409         if (cloneChildren)
410         {
411             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
412         }
413         // FIXME what about REFERENCED_PORT ?
414     }
415     else if (k == DIAGRAM)
416     {
417         if (cloneChildren)
418         {
419             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
420         }
421     }
422     else if (k == LINK)
423     {
424         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
425         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
426         deepClone(mapped, uid, o, k, SOURCE_PORT, false);
427         deepClone(mapped, uid, o, k, DESTINATION_PORT, false);
428     }
429     else if (k == PORT)
430     {
431         deepClone(mapped, uid, o, k, SOURCE_BLOCK, false);
432         deepCloneVector(mapped, uid, o, k, CONNECTED_SIGNALS, false);
433     }
434     return o;
435 }
436
437 void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
438 {
439     ScicosID v;
440     getObjectProperty(uid, k, p, v);
441
442     ScicosID cloned = 0;
443
444     std::map<ScicosID, ScicosID>::iterator it = mapped.find(v);
445     if (it != mapped.end())
446     {
447         cloned = it->second;
448     }
449     else
450     {
451         if (cloneIfNotFound)
452         {
453             if (v != 0)
454             {
455                 cloned = cloneObject(mapped, v, true, true);
456             }
457             else
458             {
459                 cloned = 0;
460             }
461         }
462         else
463         {
464             cloned = 0;
465         }
466     }
467
468     setObjectProperty(clone, k, p, cloned);
469     // When cloning a Link, connect both extremities together
470     if ((p == SOURCE_PORT || p == DESTINATION_PORT) && cloned != 0)
471     {
472         setObjectProperty(cloned, PORT, CONNECTED_SIGNALS, clone);
473     }
474 }
475
476 void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
477 {
478     std::vector<ScicosID> v;
479     getObjectProperty(uid, k, p, v);
480
481     std::vector<ScicosID> cloned;
482     cloned.reserve(v.size());
483
484     for (const ScicosID & id : v)
485     {
486         if (id == 0)
487         {
488             // Deleted Block, the cloning is done at Adapter level
489             cloned.push_back(id);
490             continue;
491         }
492
493         std::map<ScicosID, ScicosID>::iterator it = mapped.find(id);
494         if (it != mapped.end())
495         {
496             cloned.push_back(it->second);
497         }
498         else
499         {
500             if (cloneIfNotFound)
501             {
502                 if (id != 0)
503                 {
504                     cloned.push_back(cloneObject(mapped, id, true, true));
505                 }
506                 else
507                 {
508                     cloned.push_back(ScicosID());
509                 }
510             }
511             else
512             {
513                 cloned.push_back(ScicosID());
514             }
515         }
516     }
517
518     setObjectProperty(clone, k, p, cloned);
519 }
520
521 ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren, bool clonePorts)
522 {
523     std::map<ScicosID, ScicosID> mapped;
524     ScicosID clone = cloneObject(mapped, uid, cloneChildren, clonePorts);
525     CLONE_PRINT(uid, clone);
526
527     return clone;
528 }
529
530 kind_t Controller::getKind(ScicosID uid) const
531 {
532     lock(&m_instance.onModelStructuralModification);
533
534     kind_t kind = m_instance.model.getKind(uid);
535
536     unlock(&m_instance.onModelStructuralModification);
537     return kind;
538 }
539
540 std::vector<ScicosID> Controller::getAll(kind_t k) const
541 {
542     lock(&m_instance.onModelStructuralModification);
543
544     auto vec = m_instance.model.getAll(k);
545
546     unlock(&m_instance.onModelStructuralModification);
547     return vec;
548 }
549
550 void Controller::sortAndFillKind(std::vector<ScicosID>& uids, std::vector<int>& kinds)
551 {
552     lock(&m_instance.onModelStructuralModification);
553
554     // create a container of pair
555     struct local_pair
556     {
557         ScicosID first;
558         int second;
559     };
560     std::vector<local_pair> container(uids.size());
561
562     // fill it
563     for (size_t i = 0; i < uids.size(); ++i)
564     {
565         container[i] = { uids[i], m_instance.model.getKind(uids[i]) };
566     }
567
568     // sort according to the kinds
569     std::stable_sort(container.begin(), container.end(), [] (const local_pair & a, const local_pair & b)
570     {
571         return a.second < b.second;
572     });
573
574     // move things back
575     uids.clear();
576     kinds.reserve(uids.capacity());
577     for (const auto & v : container)
578     {
579         uids.push_back(v.first);
580         kinds.push_back(v.second);
581     }
582
583     unlock(&m_instance.onModelStructuralModification);
584 }
585
586
587
588 model::BaseObject* Controller::getObject(ScicosID uid) const
589 {
590     lock(&m_instance.onModelStructuralModification);
591     model::BaseObject* o = m_instance.model.getObject(uid);
592     unlock(&m_instance.onModelStructuralModification);
593     return o;
594 }
595
596 } /* namespace org_scilab_modules_scicos */