fix missing-override warnings on Scilab types
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BaseAdapter.hxx
index 4d84b0d..6db39d7 100644 (file)
@@ -1,31 +1,55 @@
 /*
- *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2014-2016 - Scilab Enterprises - Clement DAVID
+ * Copyright (C) 2017 - ESI Group - 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-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.
  *
  */
 
 #ifndef BASEADAPTER_HXX_
 #define BASEADAPTER_HXX_
 
+#include <cstring>
+
 #include <algorithm>
+#include <functional>
 #include <string>
-#include <utility>
-#include <iostream>
+#include <vector>
+#include <sstream>
 
+#include "bool.hxx"
+#include "double.hxx"
 #include "user.hxx"
+#include "int.hxx"
 #include "internal.hxx"
+#include "tlist.hxx"
+#include "mlist.hxx"
 #include "string.hxx"
-
+#include "callable.hxx"
+#include "overload.hxx"
+#include "configvariable.hxx"
+#include "exp.hxx"
+#include "types_comparison_eq.hxx"
+
+#include "view_scilab/Adapters.hxx"
+#include "view_scilab/AdapterView.hxx"
+#include "controller_helpers.hxx"
+#include "utilities.hxx"
 #include "Controller.hxx"
-#include "Adapters.hxx"
 #include "model/BaseObject.hxx"
 
+extern "C" {
+#include "localization.h"
+}
+
 namespace org_scilab_modules_scicos
 {
 namespace view_scilab
@@ -44,48 +68,110 @@ public:
     typedef std::vector< property<Adaptor> > props_t;
     typedef typename props_t::iterator props_t_it;
 
+    /*
+     * Static properties accessors
+     */
+    static props_t fields;
 
     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
+    property(const property& p) :
+        original_index(p.original_index),
+        name(p.name),
+        get(p.get),
+        set(p.set)
+    {};
     ~property() {};
+    property(property&& p) :
+        original_index(std::move(p.original_index)),
+        name(std::move(p.name)),
+        get(std::move(p.get)),
+        set(std::move(p.set))
+    {};
+    property<Adaptor>& operator= (property<Adaptor>&& p)
+    {
+        original_index = std::move(p.original_index);
+        name = std::move(p.name);
+        get = std::move(p.get);
+        set = std::move(p.set);
+        return *this;
+    };
 
-    size_t original_index;
+    int original_index;
     std::wstring name;
     getter_t get;
     setter_t set;
 
-    bool operator< (const std::wstring& v) const
+public:
+
+    /**
+     * @return true if the properties have already been setup, false otherwise.
+     */
+    static bool properties_have_not_been_set()
     {
-        return name < v;
+        return fields.empty();
     }
 
-    static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
+    /** reserve an amount of property */
+    static void reserve_properties(size_t count)
     {
-        return p1.original_index < p2.original_index;
+        fields.reserve(count);
     }
 
-    /*
-     * Static properties accessors
-     */
-    static props_t fields;
-
-    /**
-     * @return true if the properties has already been setup, false otherwise.
-     */
-    static bool properties_has_not_been_set()
+    /** compact the properties and setup for a fast lookup */
+    static void shrink_to_fit()
     {
-        return fields.empty();
+        fields.shrink_to_fit();
+        std::sort(fields.begin(), fields.end());
     }
 
-    /**
-     * Add a property to an Adaptor
-     */
+    /** add a property to an Adaptor */
     static void add_property(const std::wstring& name, getter_t g, setter_t s)
     {
-        property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
-        fields.insert(pos, property(name, g, s));
+        fields.emplace_back(property(name, g, s));
+    }
+
+    /** lookup for a name */
+    static props_t_it find(const std::wstring& name)
+    {
+        props_t_it found = std::lower_bound(fields.begin(), fields.end(), name);
+        if (found != fields.end() && *found == name)
+        {
+            return found;
+        }
+        else
+        {
+            return fields.end();
+        }
     }
 };
 
+template<typename Adaptor>
+inline bool
+operator<(const property<Adaptor>& x, const property<Adaptor>& y)
+{
+    return x.name < y.name;
+}
+
+template<typename Adaptor>
+inline bool
+operator<(const property<Adaptor>& x, const std::wstring& y)
+{
+    return x.name < y;
+}
+
+template<typename Adaptor>
+inline bool
+operator==(const property<Adaptor>& x, const property<Adaptor>& y)
+{
+    return x.name == y.name;
+}
+
+template<typename Adaptor>
+inline bool
+operator==(const property<Adaptor>& x, const std::wstring& y)
+{
+    return x.name == y;
+}
 
 /**
  * Base definition of the adapter pattern, implement the get / set dispatch.
@@ -93,13 +179,38 @@ public:
  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
  */
 template<typename Adaptor, typename Adaptee>
-class BaseAdapter : public types::User<Adaptor>
+class BaseAdapter : public types::UserType
 {
+private:
+    using BaseObject = org_scilab_modules_scicos::model::BaseObject;
 
 public:
-    BaseAdapter(Adaptee* o) : adaptee(o) {};
-    BaseAdapter(const BaseAdapter& o) : adaptee(o.adaptee) {};
-    virtual ~BaseAdapter() {};
+    explicit BaseAdapter() : m_adaptee(nullptr) {}
+    BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
+    BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
+    BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
+    {
+        if (adapter.getAdaptee() != nullptr)
+        {
+            AdapterView update_partial_information;
+            Controller controller;
+
+            Controller::cloned_t mapped;
+            BaseObject* clone = controller.cloneBaseObject(mapped, adapter.getAdaptee(), cloneChildren, true);
+            m_adaptee = static_cast<Adaptee*>(clone);
+        }
+    };
+    BaseAdapter(const BaseAdapter&& adapter) : BaseAdapter(Controller(), adapter.m_adaptee) {}
+    ~BaseAdapter()
+    {
+        if (m_adaptee != nullptr)
+        {
+            AdapterView update_partial_information;
+
+            Controller controller;
+            controller.deleteObject(m_adaptee->id());
+        }
+    };
 
     /*
      * property accessors
@@ -107,73 +218,260 @@ public:
 
     bool hasProperty(const std::wstring& _sKey) const
     {
-        typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
-        return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
+        typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
+        return found != property<Adaptor>::fields.end();
     }
 
     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
     {
-        typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
-        if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
+        typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
+        if (found != property<Adaptor>::fields.end())
         {
-            return found->get(static_cast<Adaptor*>(this), controller);
+            Adaptor& adapter = *static_cast<Adaptor*>(this);
+            return found->get(adapter, controller);
         }
-        return 0;
+        return nullptr;
     }
 
     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
     {
-        typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
-        if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
+        typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
+        if (found != property<Adaptor>::fields.end())
         {
-            return found->set(*static_cast<Adaptor*>(this), v, controller);
+            Adaptor& adapter = *static_cast<Adaptor*>(this);
+            return found->set(adapter, v, controller);
         }
         return false;
     }
 
+    void copyProperties(const Adaptor& adaptor, Controller controller = Controller())
+    {
+        for (const auto& p : property<Adaptor>::fields)
+        {
+            types::InternalType* pIT = p.get(adaptor, controller);
+            p.set(*static_cast<Adaptor*>(this), pIT, controller);
+            pIT->killMe();
+        }
+    }
+
     /**
-     * @return the Adaptee instance
+     * property as TList accessors
      */
-    Adaptee* getAdaptee() const
+
+    types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
     {
-        return adaptee;
-    };
+        const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
+
+        // create the header
+        types::String* header = new types::String(1, 1 + (int)properties.size());
+        header->set(0, Adaptor::getSharedTypeStr().c_str());
+        for (const auto& p : properties)
+        {
+            header->set(1 + p.original_index, p.name.c_str());
+
+            types::InternalType* field = p.get(*static_cast<Adaptor*>(this), controller);
+            tlist->set(1 + p.original_index, field);
+            if (field->isList())
+            {
+                field->killMe();
+            }
+
+        }
+        tlist->set(0, header);
+
+        return tlist;
+    }
+
+    bool setAsTList(types::InternalType* v, Controller& controller)
+    {
+        if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
+        {
+            get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %ls: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
+            return false;
+        }
+        types::TList* current = v->getAs<types::TList>();
+        // The input TList cannot be empty
+        if (current->getSize() < 1)
+        {
+            get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %ls: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
+            return false;
+        }
+
+        // Check the header
+        types::String* header = current->getFieldNames();
+        if (header->getSize() < 1)
+        {
+            get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for header of field \"%ls\": at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
+            return false;
+        }
+        // Make sure it is the same type as the Adapter
+        if (header->get(0) != Adaptor::getSharedTypeStr())
+        {
+            get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for header of field \"%ls\": \"%ls\" expected.\n"), Adaptor::getSharedTypeStr().c_str(), Adaptor::getSharedTypeStr().c_str());
+            return false;
+        }
+
+        // Retrieve the Adapter's properties
+        const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
+
+        // For each input property, if it corresponds to an Adapter's property, set it.
+        for (int index = 1; index < header->getSize(); ++index)
+        {
+            std::wstring name(header->get(index));
+            typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
+            if (found != properties.end())
+            {
+                bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
+                if (!status)
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
 
     /**
-     * set the adaptee
+     * property comparison
      */
-    void setAdaptee(Adaptee* adaptee)
+
+    bool operator==(const types::InternalType& o) override final
     {
-        this->adaptee = adaptee;
+
+        const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(o.getShortTypeStr());
+        // Check that 'ut' is an Adapter of the same type as *this
+        if (adapter_index == Adapters::INVALID_ADAPTER)
+        {
+            return false;
+        }
+        if (this->getTypeStr() != o.getTypeStr())
+        {
+            return false;
+        }
+
+        const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
+
+        bool internal_equal;
+        Controller controller;
+        for (const auto& p : properties)
+        {
+            types::InternalType* ith_prop1 = p.get(*static_cast<const Adaptor*>(this), controller);
+            types::InternalType* ith_prop2 = p.get(*static_cast<const Adaptor*>(&o), controller);
+
+            // loop while the inner types are equals
+            internal_equal = *ith_prop1 == *ith_prop2;
+
+            // Getting a property allocates data, so free it
+            ith_prop1->killMe();
+            ith_prop2->killMe();
+
+            if (!internal_equal)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    types::Bool* equal(types::UserType*& ut) override final
+    {
+        const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
+        // Check that 'ut' is an Adapter of the same type as *this
+        if (adapter_index == Adapters::INVALID_ADAPTER)
+        {
+            return new types::Bool(false);
+        }
+        if (this->getTypeStr() != ut->getTypeStr())
+        {
+            return new types::Bool(false);
+        }
+
+        const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
+
+        types::Bool* ret = new types::Bool(1, 1 + (int)properties.size());
+        ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
+
+        Controller controller;
+        for (const auto& p : properties)
+        {
+            types::InternalType* ith_prop1 = p.get(*static_cast<Adaptor*>(this), controller);
+            types::InternalType* ith_prop2 = p.get(*static_cast<Adaptor*>(ut), controller);
+            ret->set(p.original_index + 1, *ith_prop1 == *ith_prop2);
+
+            // Getting a property allocates data, so free them
+            ith_prop1->killMe();
+            ith_prop2->killMe();
+        }
+
+        return ret;
+    }
+
+    /**
+     * Return a default constructed Scilab value
+     */
+    template<typename T>
+    static types::InternalType* default_value()
+    {
+        T* o = new T();
+        o->IncreaseRef();
+        return o;
+    }
+
+    /**
+     * Increase reference count to store a Scilab value
+     */
+    template<typename T>
+    static T* reference_value(T* o)
+    {
+        o->IncreaseRef();
+        return o;
+    }
+
+
+    /**
+     * @return the Adaptee
+     */
+    Adaptee* getAdaptee() const
+    {
+        return m_adaptee;
     }
 
     /*
      * All following methods should be implemented by each template instance
      */
 
-    virtual std::wstring getTypeStr() = 0;
-    virtual std::wstring getShortTypeStr() = 0;
+    virtual std::wstring getTypeStr() const override = 0;
+    virtual std::wstring getShortTypeStr() const override = 0;
+
+private:
+    virtual UserType* clone() override final
+    {
+        return new Adaptor(*static_cast<Adaptor*>(this));
+    }
 
     /*
      * Implement a specific types::User
      */
-private:
-    types::InternalType* clone()
+
+    bool isAssignable() override final
     {
-        return new Adaptor(*static_cast<Adaptor*>(this));
+        return true;
     }
 
-    bool isAssignable()
+    // sb.model.rpar.contrib will return a reference to contrib
+    bool isContainer() override final
     {
         return true;
     }
 
-    bool extract(const std::wstring & name, types::InternalType *& out)
+    bool extract(const std::wstring & name, types::InternalType *& out) override final
     {
-        typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
-        if (found != property<Adaptor>::fields.end() && !(name < found->name))
+        typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
+        if (found != property<Adaptor>::fields.end())
         {
-            Controller controller = Controller();
+            Controller controller;
             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
             if (value == 0)
             {
@@ -183,34 +481,193 @@ private:
             out = value;
             return true;
         }
+
+        // specific case : to ease debugging let the user retrieve the model ID
+        if (name == L"modelID")
+        {
+            out = new types::Int64(m_adaptee->id());
+            return true;
+        }
+
         return false;
     }
 
-    void whoAmI(void)
+    types::InternalType* extract(types::typed_list* _pArgs) override final
+    {
+        if (_pArgs->size() == 0)
+        {
+            // call overload
+            return NULL;
+        }
+
+        if ((*_pArgs)[0]->isString())
+        {
+            types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
+            types::InternalType* pOut = NULL;
+            extract(std::wstring(pStr->get(0)), pOut);
+            return pOut;
+        }
+        else
+        {
+            if ((*_pArgs)[0]->isDouble())
+            {
+                types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
+
+                if (index->get(0) == 1)
+                {
+                    // When _pArgs is '1', return the list of the property names of the Adaptor
+
+                    const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
+
+                    // Allocate the return
+                    types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
+
+                    for (const auto& p : properties)
+                    {
+                        pOut->set(p.original_index, p.name.data());
+                    }
+                    return pOut;
+                }
+            }
+            else
+            {
+                // TO DO : management other type for arguments like a scalar or matrix of double
+            }
+        }
+
+        return NULL;
+    }
+
+    types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
+    {
+        for (size_t i = 0; i < _pArgs->size(); i++)
+        {
+            if ((*_pArgs)[i]->isString())
+            {
+                Controller controller;
+
+                types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
+
+                Adaptor* work;
+                if (getAdaptee()->refCount() > 0)
+                {
+                    // clone()
+                    work = new Adaptor(*static_cast<Adaptor*>(this));
+                }
+                else
+                {
+                    work = static_cast<Adaptor*>(this);
+                }
+
+                typename property<Adaptor>::props_t_it found = property<Adaptor>::find(std::wstring(pStr->get(0)));
+                if (found != property<Adaptor>::fields.end())
+                {
+                    found->set(*work, _pSource, controller);
+                }
+
+                return work;
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+
+        // call overload
+        return NULL;
+    }
+
+    void whoAmI(void) override
     {
         std::cout << "scicos object";
     }
 
-    bool toString(std::wostringstream& ostr)
+    bool hasToString() override final
     {
-        typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
-        std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
+        // Do not allow scilab to call toString of this class
+        return false;
+    }
+
+    bool toString(std::wostringstream& ostr) override final
+    {
+        // Deprecated, use the overload instead
+        const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
 
-        ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
-        for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
+        ostr << L"scicos_" <<  getTypeStr() << L" type :" << '\n';
+        for (const auto& p : properties)
         {
-            ostr << L"  " << it->name << std::endl;
+            ostr << L"  " << p.name << '\n';
         }
         return true;
     }
 
+    bool isInvokable() const override final
+    {
+        return true;
+    }
+
+    bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
+    {
+        if (in.size() == 0)
+        {
+            out.push_back(this);
+            return true;
+        }
+        else if (in.size() == 1)
+        {
+            types::InternalType* _out = nullptr;
+            types::InternalType*  arg = in[0];
+            if (arg->isString())
+            {
+                types::String* pString = arg->getAs<types::String>();
+                for (int i = 0; i < pString->getSize(); ++i)
+                {
+                    if (!extract(pString->get(i), _out))
+                    {
+                        return false;
+                    }
+                    out.push_back(_out);
+                }
+            }
+
+            if (!out.empty())
+            {
+                return true;
+            }
+        }
+
+        types::Callable::ReturnValue ret;
+        // Overload of extraction needs the BaseAdapter from where we extract
+        this->IncreaseRef();
+        in.push_back(this);
+
+        try
+        {
+            ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
+        }
+        catch (ast::InternalError & /*se*/)
+        {
+            ret = Overload::call(L"%l_e", in, 1, out);
+        }
+
+        // Remove this from "in" to keep "in" unchanged.
+        this->DecreaseRef();
+        in.pop_back();
+
+        if (ret == types::Callable::Error)
+        {
+            throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
+        }
+
+        return true;
+    }
 
 private:
-    Adaptee* adaptee;
+    Adaptee* m_adaptee;
 };
 
 
-} /* view_scilab */
+} /* namespace view_scilab */
 } /* namespace org_scilab_modules_scicos */
 
 #endif /* BASEADAPTER_HXX_ */