Xcos MVC: use std::atomic to be thread safe
[scilab.git] / scilab / modules / scicos / includes / Controller.hxx
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 #ifndef CONTROLLER_HXX_
14 #define CONTROLLER_HXX_
15
16 #include <atomic>
17 #include <string>
18 #include <vector>
19 #include <map>
20
21 #include "utilities.hxx"
22 #include "Model.hxx"
23 #include "View.hxx"
24 #include "model/BaseObject.hxx"
25
26 #include "dynlib_scicos.h"
27
28 namespace org_scilab_modules_scicos
29 {
30
31 /**
32  * Controller from the MVC pattern
33  *
34  * All calls to objects should use this controller, all usable objects are referenced by this controller.
35  */
36 class SCICOS_IMPEXP Controller
37 {
38 public:
39     static View* register_view(const std::string& name, View* v);
40     static void unregister_view(View* v);
41     static View* unregister_view(const std::string& name);
42     static View* look_for_view(const std::string& name);
43
44     Controller();
45     ~Controller();
46
47     ScicosID createObject(kind_t k);
48     unsigned referenceObject(const ScicosID uid) const;
49     template<typename T>
50     T* referenceObject(T* o) const
51     {
52         referenceObject(o->id());
53         return o;
54     }
55     void deleteObject(ScicosID uid);
56     ScicosID cloneObject(ScicosID uid, bool cloneChildren, bool clonePorts);
57
58     kind_t getKind(ScicosID uid) const;
59     std::vector<ScicosID> getAll(kind_t k) const;
60     void sortAndFillKind(std::vector<ScicosID>& uids, std::vector<int>& kind);
61     model::BaseObject* getObject(ScicosID uid) const;
62     template<typename T>
63     T* getObject(ScicosID uid) const
64     {
65         return static_cast<T*>(getObject(uid));
66     }
67
68     template<typename T>
69     bool getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, T& v) const
70     {
71         while (m_instance.onModelStructuralModification.test_and_set(std::memory_order_acquire))  // acquire lock
72             ; // spin
73         bool ret = m_instance.model.getObjectProperty(uid, k, p, v);
74         m_instance.onModelStructuralModification.clear(std::memory_order_release); // unlock
75         return ret;
76     };
77
78     template<typename T>
79     update_status_t setObjectProperty(const ScicosID& uid, kind_t k, object_properties_t p, T v)
80     {
81         while (m_instance.onModelStructuralModification.test_and_set(std::memory_order_acquire))  // acquire lock
82             ; // spin
83         update_status_t status = m_instance.model.setObjectProperty(uid, k, p, v);
84         m_instance.onModelStructuralModification.clear(std::memory_order_release); // unlock
85
86         while (m_instance.onViewsStructuralModification.test_and_set(std::memory_order_acquire))  // acquire lock
87             ; // spin
88         for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
89         {
90             (*iter)->propertyUpdated(uid, k, p, status);
91         }
92         m_instance.onViewsStructuralModification.clear(std::memory_order_release); // unlock
93         return status;
94     }
95
96 private:
97
98     typedef std::vector<View*> view_set_t;
99     typedef std::vector<std::string> view_name_set_t;
100
101     /**
102      * Shared data through all instance of the controllers
103      */
104     struct SharedData
105     {
106         std::atomic_flag onModelStructuralModification;
107         Model model;
108
109         std::atomic_flag onViewsStructuralModification;
110         view_name_set_t allNamedViews;
111         view_set_t allViews;
112
113         SharedData();
114         ~SharedData();
115     };
116
117     /**
118      * Shared instance of the data
119      *
120      * This will be allocated on-demand by Controller::get_instance()
121      */
122     static SharedData m_instance;
123
124     /*
125      * Methods
126      */
127
128     ScicosID cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren, bool clonePorts);
129     template<typename T>
130     void cloneProperties(model::BaseObject* initial, ScicosID clone);
131     void deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound);
132     void deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound);
133     void unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop);
134     void unlink(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop);
135     void deleteVector(ScicosID uid, kind_t k, object_properties_t uid_prop);
136 };
137
138 } /* namespace org_scilab_modules_scicos */
139
140 #endif /* CONTROLLER_HXX_ */