X-Git-Url: http://gitweb.scilab.org/?p=scilab.git;a=blobdiff_plain;f=scilab%2Fmodules%2Fscicos%2Fsrc%2Fcpp%2Fview_scilab%2FBaseAdapter.hxx;h=6db39d7f3550ddf6e062fb42fdc1c816c2795ae7;hp=220bf26fca221aa0008d541eb8ae535d89ed81e4;hb=025bb6738d47ccbd9093b90bc22b9710c41227c0;hpb=6f0b37a424a8119b419f6de117b2f7fcfc962d20 diff --git a/scilab/modules/scicos/src/cpp/view_scilab/BaseAdapter.hxx b/scilab/modules/scicos/src/cpp/view_scilab/BaseAdapter.hxx index 220bf26..6db39d7 100644 --- a/scilab/modules/scicos/src/cpp/view_scilab/BaseAdapter.hxx +++ b/scilab/modules/scicos/src/cpp/view_scilab/BaseAdapter.hxx @@ -1,33 +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.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. * */ #ifndef BASEADAPTER_HXX_ #define BASEADAPTER_HXX_ +#include + #include +#include #include #include #include +#include "bool.hxx" +#include "double.hxx" #include "user.hxx" +#include "int.hxx" #include "internal.hxx" -#include "mlist.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 @@ -46,29 +68,40 @@ public: typedef std::vector< property > 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& operator= (property&& 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 - { - return name < v; - } - - static bool original_index_cmp(property p1, property p2) - { - return p1.original_index < p2.original_index; - } - - /* - * Static properties accessors - */ - static props_t fields; +public: /** * @return true if the properties have already been setup, false otherwise. @@ -78,16 +111,67 @@ public: return fields.empty(); } - /** - * Add a property to an Adaptor - */ + /** reserve an amount of property */ + static void reserve_properties(size_t count) + { + fields.reserve(count); + } + + /** compact the properties and setup for a fast lookup */ + static void shrink_to_fit() + { + fields.shrink_to_fit(); + std::sort(fields.begin(), fields.end()); + } + + /** add a property to an Adaptor */ static void add_property(const std::wstring& name, getter_t g, setter_t s) { - property::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 +inline bool +operator<(const property& x, const property& y) +{ + return x.name < y.name; +} + +template +inline bool +operator<(const property& x, const std::wstring& y) +{ + return x.name < y; +} + +template +inline bool +operator==(const property& x, const property& y) +{ + return x.name == y.name; +} + +template +inline bool +operator==(const property& x, const std::wstring& y) +{ + return x.name == y; +} /** * Base definition of the adapter pattern, implement the get / set dispatch. @@ -95,13 +179,38 @@ public: * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces. */ template -class BaseAdapter : public types::User +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(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 @@ -109,102 +218,155 @@ public: bool hasProperty(const std::wstring& _sKey) const { - typename property::props_t_it found = std::lower_bound(property::fields.begin(), property::fields.end(), _sKey); - return found != property::fields.end() && !(_sKey < found->name); + typename property::props_t_it found = property::find(_sKey); + return found != property::fields.end(); } types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const { - typename property::props_t_it found = std::lower_bound(property::fields.begin(), property::fields.end(), _sKey); - if (found != property::fields.end() && !(_sKey < found->name)) + typename property::props_t_it found = property::find(_sKey); + if (found != property::fields.end()) { - return found->get(static_cast(this), controller); + Adaptor& adapter = *static_cast(this); + return found->get(adapter, controller); } - return 0; + return nullptr; } bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller()) { - typename property::props_t_it found = std::lower_bound(property::fields.begin(), property::fields.end(), _sKey); - if (found != property::fields.end() && !(_sKey < found->name)) + typename property::props_t_it found = property::find(_sKey); + if (found != property::fields.end()) { - return found->set(*static_cast(this), v, controller); + Adaptor& adapter = *static_cast(this); + return found->set(adapter, v, controller); } return false; } + void copyProperties(const Adaptor& adaptor, Controller controller = Controller()) + { + for (const auto& p : property::fields) + { + types::InternalType* pIT = p.get(adaptor, controller); + p.set(*static_cast(this), pIT, controller); + pIT->killMe(); + } + } + /** * property as TList accessors */ types::InternalType* getAsTList(types::TList* tlist, const Controller& controller) { - typename property::props_t properties = property::fields; - std::sort(properties.begin(), properties.end(), property::original_index_cmp); + const typename property::props_t& properties = property::fields; // create the header - types::String* header = new types::String(1 + properties.size(), 1); + types::String* header = new types::String(1, 1 + (int)properties.size()); header->set(0, Adaptor::getSharedTypeStr().c_str()); - int index = 1; - for (typename property::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index) + for (const auto& p : properties) { - header->set(index, it->name.c_str()); - } - tlist->set(0, header); + header->set(1 + p.original_index, p.name.c_str()); + + types::InternalType* field = p.get(*static_cast(this), controller); + tlist->set(1 + p.original_index, field); + if (field->isList()) + { + field->killMe(); + } - // set the tlist field value - index = 1; - for (typename property::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index) - { - tlist->set(index, it->get(*static_cast(this), controller)); } + tlist->set(0, header); return tlist; } bool setAsTList(types::InternalType* v, Controller& controller) { - typename property::props_t properties = property::fields; - std::sort(properties.begin(), properties.end(), property::original_index_cmp); - - if (v->getType() != types::InternalType::ScilabTList) + 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(); - if (current->getSize() != static_cast(1 + properties.size())) + // 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 + // Check the header types::String* header = current->getFieldNames(); - if (header->getSize() != static_cast(1 + properties.size())) + 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; } - int index = 1; - for (typename property::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index) + + // Retrieve the Adapter's properties + const typename property::props_t& properties = property::fields; + + // For each input property, if it corresponds to an Adapter's property, set it. + for (int index = 1; index < header->getSize(); ++index) { - if (header->get(index) != it->name) + std::wstring name(header->get(index)); + typename property::props_t_it found = property::find(name); + if (found != properties.end()) { - return false; + bool status = found->set(*static_cast(this), current->get(index), controller); + if (!status) + { + return false; + } } } - // this is a valid tlist, get each tlist field value and pass it to the right property decoder - index = 1; - for (typename property::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index) + return true; + } + + /** + * property comparison + */ + + bool operator==(const types::InternalType& o) override final + { + + 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::props_t& properties = property::fields; + + bool internal_equal; + Controller controller; + for (const auto& p : properties) { - // DEBUG LOG: - // std::wcerr << Adaptor::getSharedTypeStr() << L" set " << it->name << std::endl; + types::InternalType* ith_prop1 = p.get(*static_cast(this), controller); + types::InternalType* ith_prop2 = p.get(*static_cast(&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(); - bool status = it->set(*static_cast(this), current->get(index), controller); - if (!status) + if (!internal_equal) { return false; } @@ -213,49 +375,103 @@ public: 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::props_t& properties = property::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(this), controller); + types::InternalType* ith_prop2 = p.get(*static_cast(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 the Adaptee instance + * Return a default constructed Scilab value */ - Adaptee* getAdaptee() const + template + static types::InternalType* default_value() { - return adaptee; - }; + T* o = new T(); + o->IncreaseRef(); + return o; + } + + /** + * Increase reference count to store a Scilab value + */ + template + static T* reference_value(T* o) + { + o->IncreaseRef(); + return o; + } + /** - * set the adaptee + * @return the Adaptee */ - void setAdaptee(Adaptee* adaptee) + Adaptee* getAdaptee() const { - this->adaptee = adaptee; + 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(this)); + } /* * Implement a specific types::User */ -private: - types::InternalType* clone() + + bool isAssignable() override final { - return new Adaptor(*static_cast(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::props_t_it found = std::lower_bound(property::fields.begin(), property::fields.end(), name); - if (found != property::fields.end() && !(name < found->name)) + typename property::props_t_it found = property::find(name); + if (found != property::fields.end()) { - Controller controller = Controller(); + Controller controller; types::InternalType* value = found->get(*static_cast(this), controller); if (value == 0) { @@ -265,30 +481,189 @@ 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::InternalType* pOut = NULL; + extract(std::wstring(pStr->get(0)), pOut); + return pOut; + } + else + { + if ((*_pArgs)[0]->isDouble()) + { + types::Double* index = (*_pArgs)[0]->getAs(); + + if (index->get(0) == 1) + { + // When _pArgs is '1', return the list of the property names of the Adaptor + + const typename property::props_t& properties = property::fields; + + // Allocate the return + types::String* pOut = new types::String(1, static_cast(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(); + + Adaptor* work; + if (getAdaptee()->refCount() > 0) + { + // clone() + work = new Adaptor(*static_cast(this)); + } + else + { + work = static_cast(this); + } + + typename property::props_t_it found = property::find(std::wstring(pStr->get(0))); + if (found != property::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 + { + // Do not allow scilab to call toString of this class + return false; + } + + bool toString(std::wostringstream& ostr) override final { - typename property::props_t properties = property::fields; - std::sort(properties.begin(), properties.end(), property::original_index_cmp); + // Deprecated, use the overload instead + const typename property::props_t& properties = property::fields; - ostr << L"scicos_" << getTypeStr() << L" type :" << std::endl; - for (typename property::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(); + 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; };