[Coverity 1350443] Scicos src: Check function return
[scilab.git] / scilab / modules / scicos / src / cpp / Controller.cpp
index 7a4ec4a..354d7f5 100644 (file)
@@ -2,20 +2,26 @@
  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
  *
- *  This file must be used under the terms of the CeCILL.
- *  This source file is licensed as described in the file COPYING, which
- *  you should have received as part of this distribution.  The terms
- *  are also available at
- *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ *
+ * This file is hereby licensed under the terms of the GNU GPL v2.0,
+ * pursuant to article 5.3.4 of the CeCILL v.2.1.
+ * This file was originally licensed under the terms of the CeCILL v2.1,
+ * and continues to be available under such terms.
+ * For more information, see the COPYING file which you should have received
+ * along with this program.
  *
  */
 
+#include <atomic>
 #include <string>
 #include <vector>
 #include <map>
 #include <utility>
 #include <algorithm>
+#include <iterator>
 
+#include "utilities.hxx"
 
 #define REF_DEBUG 0
 #if REF_DEBUG
        do { \
        std::stringstream print; \
        print << "referenceObject( " << uid << " ) : " << refCount << std::endl; \
-       scilabWrite(print.str().data()); \
+       scilabForcedWrite(print.str().data()); \
        } while(0)
 #define UNREF_PRINT(uid, count) \
        do { \
        std::stringstream print; \
        print << "unreferenceObject( " << uid << " ) : " << refCount << std::endl; \
-       scilabWrite(print.str().data()); \
+       scilabForcedWrite(print.str().data()); \
        } while(0)
 #define CLONE_PRINT(uid, clone) \
        do { \
        std::stringstream print; \
        print << "cloneObject( " << uid << " ) : " << clone << std::endl; \
-       scilabWrite(print.str().data()); \
+       scilabForcedWrite(print.str().data()); \
        } while(0)
 #else
 #define REF_PRINT(uid, refCount)
 #endif
 
 #include "Controller.hxx"
+#include "model/BaseObject.hxx"
 
 #include "LoggerView.hxx"
 
 namespace org_scilab_modules_scicos
 {
 
+static inline void lock(std::atomic_flag* m)
+{
+    while (m->test_and_set(std::memory_order_acquire))  // acquire lock
+        ; // spin
+}
+
+static inline void unlock(std::atomic_flag* m)
+{
+    m->clear(std::memory_order_release);
+}
+
 /*
  * Implement SharedData methods
  */
 Controller::SharedData::SharedData() :
-    model(), allNamedViews(), allViews()
+    onModelStructuralModification(), model(),
+    onViewsStructuralModification(), allNamedViews(), allViews()
 {
+    unlock(&onModelStructuralModification);
+    unlock(&onViewsStructuralModification);
 }
 
 Controller::SharedData::~SharedData()
 {
-    for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
+    lock(&onViewsStructuralModification);
+    for (view_set_t::iterator iter = allViews.begin(); iter != allViews.end(); ++iter)
     {
         delete *iter;
     }
+    unlock(&onViewsStructuralModification);
 }
 
 Controller::SharedData Controller::m_instance;
 
 View* Controller::register_view(const std::string& name, View* v)
 {
+    lock(&m_instance.onViewsStructuralModification);
+
     m_instance.allNamedViews.push_back(name);
     m_instance.allViews.push_back(v);
+
+    unlock(&m_instance.onViewsStructuralModification);
     return v;
 }
 
 void Controller::unregister_view(View* v)
 {
+    lock(&m_instance.onViewsStructuralModification);
+
     view_set_t::iterator it = std::find(m_instance.allViews.begin(), m_instance.allViews.end(), v);
     if (it != m_instance.allViews.end())
     {
@@ -85,12 +114,16 @@ void Controller::unregister_view(View* v)
         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
         m_instance.allViews.erase(m_instance.allViews.begin() + d);
     }
+
+    unlock(&m_instance.onViewsStructuralModification);
 }
 
 View* Controller::unregister_view(const std::string& name)
 {
     View* view = nullptr;
 
+    lock(&m_instance.onViewsStructuralModification);
+
     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
     if (it != m_instance.allNamedViews.end())
     {
@@ -99,6 +132,7 @@ View* Controller::unregister_view(const std::string& name)
         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
         m_instance.allViews.erase(m_instance.allViews.begin() + d);
     }
+    unlock(&m_instance.onViewsStructuralModification);
 
     return view;
 }
@@ -107,12 +141,14 @@ View* Controller::look_for_view(const std::string& name)
 {
     View* view = nullptr;
 
+    lock(&m_instance.onViewsStructuralModification);
     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
     if (it != m_instance.allNamedViews.end())
     {
         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
         view = *(m_instance.allViews.begin() + d);
     }
+    unlock(&m_instance.onViewsStructuralModification);
 
     return view;
 }
@@ -127,20 +163,42 @@ Controller::~Controller()
 
 ScicosID Controller::createObject(kind_t k)
 {
+    lock(&m_instance.onModelStructuralModification);
     ScicosID uid = m_instance.model.createObject(k);
+    unlock(&m_instance.onModelStructuralModification);
 
+    lock(&m_instance.onViewsStructuralModification);
     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
     {
         (*iter)->objectCreated(uid, k);
     }
+    unlock(&m_instance.onViewsStructuralModification);
 
     return uid;
 }
 
 unsigned Controller::referenceObject(const ScicosID uid) const
 {
+    lock(&m_instance.onModelStructuralModification);
+
     unsigned refCount = m_instance.model.referenceObject(uid);
     REF_PRINT(uid, refCount);
+
+    auto o = m_instance.model.getObject(uid);
+    unlock(&m_instance.onModelStructuralModification);
+    if (o == nullptr)
+    {
+        // defensive programming
+        return 0u;
+    }
+
+    lock(&m_instance.onViewsStructuralModification);
+    for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
+    {
+        (*iter)->objectReferenced(uid, o->kind(), refCount);
+    }
+    unlock(&m_instance.onViewsStructuralModification);
+
     return refCount;
 }
 
@@ -152,18 +210,35 @@ void Controller::deleteObject(ScicosID uid)
         return;
     }
 
+    lock(&m_instance.onModelStructuralModification);
+
+    auto initial = m_instance.model.getObject(uid);
+    if (initial == nullptr)
+    {
+        // defensive programming
+        unlock(&m_instance.onModelStructuralModification);
+        return;
+    }
+    const kind_t k = initial->kind();
+
     // if this object has been referenced somewhere else do not delete it but decrement the reference counter
     unsigned& refCount = m_instance.model.referenceCount(uid);
+    unlock(&m_instance.onModelStructuralModification);
     if (refCount > 0)
     {
         --refCount;
         UNREF_PRINT(uid, refCount);
+
+        lock(&m_instance.onViewsStructuralModification);
+        for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
+        {
+            (*iter)->objectUnreferenced(uid, k, refCount);
+        }
+        unlock(&m_instance.onViewsStructuralModification);
         return;
     }
 
     // We need to delete this object and cleanup all the referenced model object
-    auto initial = getObject(uid);
-    const kind_t k = initial->kind();
 
     // disconnect / remove references of weak connected objects and decrement the reference count of all strongly connected objects.
     if (k == ANNOTATION)
@@ -211,12 +286,16 @@ void Controller::deleteObject(ScicosID uid)
     }
 
     // delete the object
+    lock(&m_instance.onModelStructuralModification);
     m_instance.model.deleteObject(uid);
+    unlock(&m_instance.onModelStructuralModification);
 
+    lock(&m_instance.onViewsStructuralModification);
     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
     {
         (*iter)->objectDeleted(uid, k);
     }
+    unlock(&m_instance.onViewsStructuralModification);
 }
 
 void Controller::unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
@@ -226,6 +305,10 @@ void Controller::unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_pr
     if (v != 0)
     {
         auto o = getObject(v);
+        if (o == nullptr)
+        {
+            return;
+        }
 
         std::vector<ScicosID> children;
         getObjectProperty(o->id(), o->kind(), ref_prop, children);
@@ -249,6 +332,11 @@ void Controller::unlink(ScicosID uid, kind_t k, object_properties_t uid_prop, ob
         if (id != 0)
         {
             auto o = getObject(id);
+            if (o == nullptr)
+            {
+                continue;
+            }
+
             // Find which end of the link is connected to the port
             ScicosID oppositeRef;
             getObjectProperty(o->id(), o->kind(), ref_prop, oppositeRef);
@@ -271,7 +359,23 @@ void Controller::deleteVector(ScicosID uid, kind_t k, object_properties_t uid_pr
     }
 }
 
-ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren)
+template<typename T>
+void Controller::cloneProperties(model::BaseObject* initial, ScicosID clone)
+{
+    for (int i = 0; i < MAX_OBJECT_PROPERTIES; ++i)
+    {
+        enum object_properties_t p = static_cast<enum object_properties_t>(i);
+
+        T value;
+        bool status = getObjectProperty(initial->id(), initial->kind(), p, value);
+        if (status)
+        {
+            setObjectProperty(clone, initial->kind(), p, value);
+        }
+    }
+}
+
+ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren, bool clonePorts)
 {
     auto initial = getObject(uid);
     const kind_t k = initial->kind();
@@ -297,10 +401,14 @@ ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID
     else if (k == BLOCK)
     {
         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
-        deepCloneVector(mapped, uid, o, k, INPUTS, true);
-        deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
-        deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
-        deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
+        if (clonePorts)
+        {
+            // Only copy the block, without any port
+            deepCloneVector(mapped, uid, o, k, INPUTS, true);
+            deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
+            deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
+            deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
+        }
 
         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
         if (cloneChildren)
@@ -328,7 +436,6 @@ ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID
         deepClone(mapped, uid, o, k, SOURCE_BLOCK, false);
         deepCloneVector(mapped, uid, o, k, CONNECTED_SIGNALS, false);
     }
-
     return o;
 }
 
@@ -350,7 +457,7 @@ void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, S
         {
             if (v != 0)
             {
-                cloned = cloneObject(mapped, v, true);
+                cloned = cloneObject(mapped, v, true, true);
             }
             else
             {
@@ -364,6 +471,11 @@ void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, S
     }
 
     setObjectProperty(clone, k, p, cloned);
+    // When cloning a Link, connect both extremities together
+    if ((p == SOURCE_PORT || p == DESTINATION_PORT) && cloned != 0)
+    {
+        setObjectProperty(cloned, PORT, CONNECTED_SIGNALS, clone);
+    }
 }
 
 void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
@@ -386,6 +498,22 @@ void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID
         std::map<ScicosID, ScicosID>::iterator it = mapped.find(id);
         if (it != mapped.end())
         {
+            if (k == PORT)
+            {
+                // We get here if we are cloning a block connected to a link that comes before itself in the objects list,
+                // so which has already been cloned but could not be connected yet.
+                int port_kind;
+                getObjectProperty(clone, PORT, PORT_KIND, port_kind);
+                if (port_kind == PORT_IN || port_kind == PORT_EIN)
+                {
+                    setObjectProperty(it->second, LINK, DESTINATION_PORT, clone);
+                }
+                else
+                {
+                    // FIXME: fix case for implicit ports, in which case connect the first unconnected link end, it doesn't matter which one
+                    setObjectProperty(it->second, LINK, SOURCE_PORT, clone);
+                }
+            }
             cloned.push_back(it->second);
         }
         else
@@ -394,16 +522,16 @@ void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID
             {
                 if (id != 0)
                 {
-                    cloned.push_back(cloneObject(mapped, id, true));
+                    cloned.push_back(cloneObject(mapped, id, true, true));
                 }
                 else
                 {
-                    cloned.push_back(0);
+                    cloned.push_back(ScicosID());
                 }
             }
             else
             {
-                cloned.push_back(0);
+                cloned.push_back(ScicosID());
             }
         }
     }
@@ -411,17 +539,185 @@ void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID
     setObjectProperty(clone, k, p, cloned);
 }
 
-ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren)
+ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren, bool clonePorts)
 {
     std::map<ScicosID, ScicosID> mapped;
-    ScicosID clone = cloneObject(mapped, uid, cloneChildren);
+    ScicosID clone = cloneObject(mapped, uid, cloneChildren, clonePorts);
     CLONE_PRINT(uid, clone);
+
     return clone;
 }
 
+kind_t Controller::getKind(ScicosID uid) const
+{
+    lock(&m_instance.onModelStructuralModification);
+
+    kind_t kind = m_instance.model.getKind(uid);
+
+    unlock(&m_instance.onModelStructuralModification);
+    return kind;
+}
+
+std::vector<ScicosID> Controller::getAll(kind_t k) const
+{
+    lock(&m_instance.onModelStructuralModification);
+
+    auto vec = m_instance.model.getAll(k);
+
+    unlock(&m_instance.onModelStructuralModification);
+    return vec;
+}
+
+void Controller::sortAndFillKind(std::vector<ScicosID>& uids, std::vector<int>& kinds)
+{
+    lock(&m_instance.onModelStructuralModification);
+
+    // create a container of pair
+    struct local_pair
+    {
+        ScicosID first;
+        int second;
+    };
+    std::vector<local_pair> container(uids.size());
+
+    // fill it
+    for (size_t i = 0; i < uids.size(); ++i)
+    {
+        container[i] = { uids[i], m_instance.model.getKind(uids[i]) };
+    }
+
+    // sort according to the kinds
+    std::stable_sort(container.begin(), container.end(), [] (const local_pair & a, const local_pair & b)
+    {
+        return a.second < b.second;
+    });
+
+    // move things back
+    uids.clear();
+    kinds.reserve(uids.capacity());
+    for (const auto & v : container)
+    {
+        uids.push_back(v.first);
+        kinds.push_back(v.second);
+    }
+
+    unlock(&m_instance.onModelStructuralModification);
+}
+
+template<typename T>
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, T& v) const
+{
+    lock(&m_instance.onModelStructuralModification);
+    bool ret = m_instance.model.getObjectProperty(uid, k, p, v);
+    unlock(&m_instance.onModelStructuralModification);
+    return ret;
+}
+
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, double& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, int& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, bool& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::string& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, ScicosID& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<double>& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<int>& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<bool>& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector< std::string >& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<ScicosID>& v) const
+{
+    return getObjectProperty<>(uid, k, p, v);
+}
+
+template<typename T>
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, T v)
+{
+    lock(&m_instance.onModelStructuralModification);
+    update_status_t status = m_instance.model.setObjectProperty(uid, k, p, v);
+    unlock(&m_instance.onModelStructuralModification);
+
+    lock(&m_instance.onViewsStructuralModification);
+    for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
+    {
+        (*iter)->propertyUpdated(uid, k, p, status);
+    }
+    unlock(&m_instance.onViewsStructuralModification);
+    return status;
+}
+
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, double v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, int v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, bool v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, ScicosID v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::string& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<double>& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<int>& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<bool>& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector< std::string >& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<ScicosID>& v)
+{
+    return setObjectProperty<>(uid, k, p, v);
+}
+
 model::BaseObject* Controller::getObject(ScicosID uid) const
 {
-    return m_instance.model.getObject(uid);
+    lock(&m_instance.onModelStructuralModification);
+    model::BaseObject* o = m_instance.model.getObject(uid);
+    unlock(&m_instance.onModelStructuralModification);
+    return o;
 }
 
 } /* namespace org_scilab_modules_scicos */
+