2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2014-2016 - Scilab Enterprises - Clement DAVID
4 * Copyright (C) 2017 - ESI Group - Clement DAVID
6 * Copyright (C) 2012 - 2016 - Scilab Enterprises
8 * This file is hereby licensed under the terms of the GNU GPL v2.0,
9 * pursuant to article 5.3.4 of the CeCILL v.2.1.
10 * This file was originally licensed under the terms of the CeCILL v2.1,
11 * and continues to be available under such terms.
12 * For more information, see the COPYING file which you should have received
13 * along with this program.
17 #ifndef BASEADAPTER_HXX_
18 #define BASEADAPTER_HXX_
32 #include "internal.hxx"
36 #include "callable.hxx"
37 #include "overload.hxx"
38 #include "configvariable.hxx"
40 #include "types_comparison_eq.hxx"
42 #include "view_scilab/Adapters.hxx"
43 #include "view_scilab/AdapterView.hxx"
44 #include "controller_helpers.hxx"
45 #include "utilities.hxx"
46 #include "Controller.hxx"
47 #include "model/BaseObject.hxx"
50 #include "localization.h"
53 namespace org_scilab_modules_scicos
59 * A property used as a getter/setter for a specific name
61 template<typename Adaptor>
65 typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
66 typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
68 typedef std::vector< property<Adaptor> > props_t;
69 typedef typename props_t::iterator props_t_it;
72 * Static properties accessors
74 static props_t fields;
76 property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
77 property(const property& p) :
78 original_index(p.original_index),
84 property(property&& p) :
85 original_index(std::move(p.original_index)),
86 name(std::move(p.name)),
87 get(std::move(p.get)),
90 property<Adaptor>& operator= (property<Adaptor>&& p)
92 original_index = std::move(p.original_index);
93 name = std::move(p.name);
94 get = std::move(p.get);
95 set = std::move(p.set);
107 * @return true if the properties have already been setup, false otherwise.
109 static bool properties_have_not_been_set()
111 return fields.empty();
114 /** reserve an amount of property */
115 static void reserve_properties(size_t count)
117 fields.reserve(count);
120 /** compact the properties and setup for a fast lookup */
121 static void shrink_to_fit()
123 fields.shrink_to_fit();
124 std::sort(fields.begin(), fields.end());
127 /** add a property to an Adaptor */
128 static void add_property(const std::wstring& name, getter_t g, setter_t s)
130 fields.emplace_back(property(name, g, s));
133 /** lookup for a name */
134 static props_t_it find(const std::wstring& name)
136 props_t_it found = std::lower_bound(fields.begin(), fields.end(), name);
137 if (found != fields.end() && *found == name)
148 template<typename Adaptor>
150 operator<(const property<Adaptor>& x, const property<Adaptor>& y)
152 return x.name < y.name;
155 template<typename Adaptor>
157 operator<(const property<Adaptor>& x, const std::wstring& y)
162 template<typename Adaptor>
164 operator==(const property<Adaptor>& x, const property<Adaptor>& y)
166 return x.name == y.name;
169 template<typename Adaptor>
171 operator==(const property<Adaptor>& x, const std::wstring& y)
177 * Base definition of the adapter pattern, implement the get / set dispatch.
179 * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
181 template<typename Adaptor, typename Adaptee>
182 class BaseAdapter : public types::UserType
185 using BaseObject = org_scilab_modules_scicos::model::BaseObject;
188 explicit BaseAdapter() : m_adaptee(nullptr) {}
189 BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
190 BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
191 BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
193 if (adapter.getAdaptee() != nullptr)
195 AdapterView update_partial_information;
196 Controller controller;
198 Controller::cloned_t mapped;
199 BaseObject* clone = controller.cloneBaseObject(mapped, adapter.getAdaptee(), cloneChildren, true);
200 m_adaptee = static_cast<Adaptee*>(clone);
203 BaseAdapter(const BaseAdapter&& adapter) : BaseAdapter(Controller(), adapter.m_adaptee) {}
206 if (m_adaptee != nullptr)
208 AdapterView update_partial_information;
210 Controller controller;
211 controller.deleteObject(m_adaptee->id());
219 bool hasProperty(const std::wstring& _sKey) const
221 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
222 return found != property<Adaptor>::fields.end();
225 types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
227 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
228 if (found != property<Adaptor>::fields.end())
230 Adaptor& adapter = *static_cast<Adaptor*>(this);
231 return found->get(adapter, controller);
236 bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
238 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
239 if (found != property<Adaptor>::fields.end())
241 Adaptor& adapter = *static_cast<Adaptor*>(this);
242 return found->set(adapter, v, controller);
247 void copyProperties(const Adaptor& adaptor, Controller controller = Controller())
249 for (const auto& p : property<Adaptor>::fields)
251 types::InternalType* pIT = p.get(adaptor, controller);
252 p.set(*static_cast<Adaptor*>(this), pIT, controller);
258 * property as TList accessors
261 types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
263 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
266 types::String* header = new types::String(1, 1 + (int)properties.size());
267 header->set(0, Adaptor::getSharedTypeStr().c_str());
268 for (const auto& p : properties)
270 header->set(1 + p.original_index, p.name.c_str());
272 types::InternalType* field = p.get(*static_cast<Adaptor*>(this), controller);
273 tlist->set(1 + p.original_index, field);
280 tlist->set(0, header);
285 bool setAsTList(types::InternalType* v, Controller& controller)
287 if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
289 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %ls: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
292 types::TList* current = v->getAs<types::TList>();
293 // The input TList cannot be empty
294 if (current->getSize() < 1)
296 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %ls: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
301 types::String* header = current->getFieldNames();
302 if (header->getSize() < 1)
304 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);
307 // Make sure it is the same type as the Adapter
308 if (header->get(0) != Adaptor::getSharedTypeStr())
310 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());
314 // Retrieve the Adapter's properties
315 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
317 // For each input property, if it corresponds to an Adapter's property, set it.
318 for (int index = 1; index < header->getSize(); ++index)
320 std::wstring name(header->get(index));
321 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
322 if (found != properties.end())
324 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
336 * property comparison
339 bool operator==(const types::InternalType& o) override final
342 const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(o.getShortTypeStr());
343 // Check that 'ut' is an Adapter of the same type as *this
344 if (adapter_index == Adapters::INVALID_ADAPTER)
348 if (this->getTypeStr() != o.getTypeStr())
353 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
356 Controller controller;
357 for (const auto& p : properties)
359 types::InternalType* ith_prop1 = p.get(*static_cast<const Adaptor*>(this), controller);
360 types::InternalType* ith_prop2 = p.get(*static_cast<const Adaptor*>(&o), controller);
362 // loop while the inner types are equals
363 internal_equal = *ith_prop1 == *ith_prop2;
365 // Getting a property allocates data, so free it
378 types::Bool* equal(types::UserType*& ut) override final
380 const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
381 // Check that 'ut' is an Adapter of the same type as *this
382 if (adapter_index == Adapters::INVALID_ADAPTER)
384 return new types::Bool(false);
386 if (this->getTypeStr() != ut->getTypeStr())
388 return new types::Bool(false);
391 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
393 types::Bool* ret = new types::Bool(1, 1 + (int)properties.size());
394 ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
396 Controller controller;
397 for (const auto& p : properties)
399 types::InternalType* ith_prop1 = p.get(*static_cast<Adaptor*>(this), controller);
400 types::InternalType* ith_prop2 = p.get(*static_cast<Adaptor*>(ut), controller);
401 ret->set(p.original_index + 1, *ith_prop1 == *ith_prop2);
403 // Getting a property allocates data, so free them
412 * Return a default constructed Scilab value
415 static types::InternalType* default_value()
423 * Increase reference count to store a Scilab value
426 static T* reference_value(T* o)
434 * @return the Adaptee
436 Adaptee* getAdaptee() const
442 * All following methods should be implemented by each template instance
445 virtual std::wstring getTypeStr() const override = 0;
446 virtual std::wstring getShortTypeStr() const override = 0;
449 virtual UserType* clone() override final
451 return new Adaptor(*static_cast<Adaptor*>(this));
455 * Implement a specific types::User
458 bool isAssignable() override final
463 // sb.model.rpar.contrib will return a reference to contrib
464 bool isContainer() override final
469 bool extract(const std::wstring & name, types::InternalType *& out) override final
471 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
472 if (found != property<Adaptor>::fields.end())
474 Controller controller;
475 types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
485 // specific case : to ease debugging let the user retrieve the model ID
486 if (name == L"modelID")
488 out = new types::Int64(m_adaptee->id());
495 types::InternalType* extract(types::typed_list* _pArgs) override final
497 if (_pArgs->size() == 0)
503 if ((*_pArgs)[0]->isString())
505 types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
506 types::InternalType* pOut = NULL;
507 extract(std::wstring(pStr->get(0)), pOut);
512 if ((*_pArgs)[0]->isDouble())
514 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
516 if (index->get(0) == 1)
518 // When _pArgs is '1', return the list of the property names of the Adaptor
520 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
522 // Allocate the return
523 types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
525 for (const auto& p : properties)
527 pOut->set(p.original_index, p.name.data());
534 // TO DO : management other type for arguments like a scalar or matrix of double
541 types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
543 for (size_t i = 0; i < _pArgs->size(); i++)
545 if ((*_pArgs)[i]->isString())
547 Controller controller;
549 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
552 if (getAdaptee()->refCount() > 0)
555 work = new Adaptor(*static_cast<Adaptor*>(this));
559 work = static_cast<Adaptor*>(this);
562 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(std::wstring(pStr->get(0)));
563 if (found != property<Adaptor>::fields.end())
565 found->set(*work, _pSource, controller);
580 void whoAmI(void) override
582 std::cout << "scicos object";
585 bool hasToString() override final
587 // Do not allow scilab to call toString of this class
591 bool toString(std::wostringstream& ostr) override final
593 // Deprecated, use the overload instead
594 const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
596 ostr << L"scicos_" << getTypeStr() << L" type :" << '\n';
597 for (const auto& p : properties)
599 ostr << L" " << p.name << '\n';
604 bool isInvokable() const override final
609 bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
616 else if (in.size() == 1)
618 types::InternalType* _out = nullptr;
619 types::InternalType* arg = in[0];
622 types::String* pString = arg->getAs<types::String>();
623 for (int i = 0; i < pString->getSize(); ++i)
625 if (!extract(pString->get(i), _out))
639 types::Callable::ReturnValue ret;
640 // Overload of extraction needs the BaseAdapter from where we extract
646 ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
648 catch (ast::InternalError & /*se*/)
650 ret = Overload::call(L"%l_e", in, 1, out);
653 // Remove this from "in" to keep "in" unchanged.
657 if (ret == types::Callable::Error)
659 throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
670 } /* namespace view_scilab */
671 } /* namespace org_scilab_modules_scicos */
673 #endif /* BASEADAPTER_HXX_ */