2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
7 * This file is hereby licensed under the terms of the GNU GPL v2.0,
8 * pursuant to article 5.3.4 of the CeCILL v.2.1.
9 * This file was originally licensed under the terms of the CeCILL v2.1,
10 * and continues to be available under such terms.
11 * For more information, see the COPYING file which you should have received
12 * along with this program.
16 #ifndef BASEADAPTER_HXX_
17 #define BASEADAPTER_HXX_
30 #include "internal.hxx"
34 #include "callable.hxx"
35 #include "overload.hxx"
36 #include "configvariable.hxx"
39 #include "view_scilab/Adapters.hxx"
40 #include "controller_helpers.hxx"
41 #include "utilities.hxx"
42 #include "Controller.hxx"
43 #include "model/BaseObject.hxx"
46 #include "localization.h"
49 namespace org_scilab_modules_scicos
55 * A property used as a getter/setter for a specific name
57 template<typename Adaptor>
61 typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
62 typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
64 typedef std::vector< property<Adaptor> > props_t;
65 typedef typename props_t::iterator props_t_it;
68 property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
71 size_t original_index;
76 bool operator< (const std::wstring& v) const
81 static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
83 return p1.original_index < p2.original_index;
87 * Static properties accessors
89 static props_t fields;
92 * @return true if the properties have already been setup, false otherwise.
94 static bool properties_have_not_been_set()
96 return fields.empty();
100 * Add a property to an Adaptor
102 static void add_property(const std::wstring& name, getter_t g, setter_t s)
104 property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
105 fields.insert(pos, property(name, g, s));
110 * Base definition of the adapter pattern, implement the get / set dispatch.
112 * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
114 template<typename Adaptor, typename Adaptee>
115 class BaseAdapter : public types::UserType
119 BaseAdapter() : m_adaptee(nullptr) {};
120 BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
121 BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
122 BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
124 Controller controller;
125 ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren, true);
126 m_adaptee = controller.getObject< Adaptee >(id);
130 if (m_adaptee != nullptr)
132 Controller controller;
133 controller.deleteObject(m_adaptee->id());
141 bool hasProperty(const std::wstring& _sKey) const
143 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
144 return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
147 types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
149 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
150 if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
152 return found->get(static_cast<Adaptor*>(this), controller);
157 bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
159 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
160 if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
162 return found->set(*static_cast<Adaptor*>(this), v, controller);
168 * property as TList accessors
171 types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
173 typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
174 std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
177 types::String* header = new types::String(1, 1 + (int)properties.size());
178 header->set(0, Adaptor::getSharedTypeStr().c_str());
180 for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
182 header->set(index, it->name.c_str());
184 tlist->append(header);
186 // set the tlist field value
187 for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
189 types::InternalType* field = it->get(*static_cast<Adaptor*>(this), controller);
190 tlist->append(field);
200 bool setAsTList(types::InternalType* v, Controller& controller)
202 if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
204 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
207 types::TList* current = v->getAs<types::TList>();
208 // The input TList cannot be empty
209 if (current->getSize() < 1)
211 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
216 types::String* header = current->getFieldNames();
217 if (header->getSize() < 1)
219 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for header of field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
222 // Make sure it is the same type as the Adapter
223 if (header->get(0) != Adaptor::getSharedTypeStr())
225 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for header of field %s: %s expected.\n"), Adaptor::getSharedTypeStr().c_str(), Adaptor::getSharedTypeStr().c_str());
229 // Retrieve the Adapter's properties
230 typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
232 // For each input property, if it corresponds to an Adapter's property, set it.
233 for (int index = 1; index < header->getSize(); ++index)
235 typename property<Adaptor>::props_t_it found = std::lower_bound(properties.begin(), properties.end(), header->get(index));
236 if (found != properties.end() && !(header->get(index) < found->name))
238 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
250 * property comparison
253 types::Bool* equal(types::UserType*& ut) override final
255 const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
256 // Check that 'ut' is an Adapter of the same type as *this
257 if (adapter_index == Adapters::INVALID_ADAPTER)
259 return new types::Bool(false);
261 if (this->getTypeStr() != ut->getTypeStr())
263 return new types::Bool(false);
266 typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
267 std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
269 types::Bool* ret = new types::Bool(1, 1 + properties.size());
270 ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
272 Controller controller;
274 for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
276 types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
277 types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
278 ret->set(index, *ith_prop1 == *ith_prop2);
280 // Getting a property allocates data, so free it
289 * @return the Adaptee
291 Adaptee* getAdaptee() const
297 * All following methods should be implemented by each template instance
300 virtual std::wstring getTypeStr() = 0;
301 virtual std::wstring getShortTypeStr() = 0;
304 virtual UserType* clone() override final
306 return new Adaptor(*static_cast<Adaptor*>(this));
310 * Implement a specific types::User
313 bool isAssignable() override final
318 bool extract(const std::wstring & name, types::InternalType *& out) override final
320 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
321 if (found != property<Adaptor>::fields.end() && !(name < found->name))
323 Controller controller;
324 types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
334 // specific case : to ease debugging let the user retrieve the model ID
335 if (name == L"modelID")
337 out = new types::Int64(m_adaptee->id());
344 types::InternalType* extract(types::typed_list* _pArgs) override final
346 if (_pArgs->size() == 0)
352 if ((*_pArgs)[0]->isString())
354 types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
355 types::InternalType* pOut = NULL;
356 extract(std::wstring(pStr->get(0)), pOut);
361 if ((*_pArgs)[0]->isDouble())
363 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
365 if (index->get(0) == 1)
367 // When _pArgs is '1', return the list of the property names of the Adaptor
369 // Sort the properties before extracting them
370 typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
371 std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
373 // Allocate the return
374 types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
377 for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
379 pOut->set(i, it->name.data());
386 // TO DO : management other type for arguments like a scalar or matrix of double
393 types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
395 for (size_t i = 0; i < _pArgs->size(); i++)
397 if ((*_pArgs)[i]->isString())
399 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
400 std::wstring name = pStr->get(0);
402 Controller controller;
403 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
404 if (found != property<Adaptor>::fields.end() && !(name < found->name))
406 found->set(*static_cast<Adaptor*>(this), _pSource, controller);
421 void whoAmI(void) override
423 std::cout << "scicos object";
426 bool hasToString() override final
428 // Do not allow scilab to call toString of this class
432 bool toString(std::wostringstream& ostr) override final
434 // Deprecated, use the overload instead
435 typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
436 std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
438 ostr << L"scicos_" << getTypeStr() << L" type :" << '\n';
439 for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
441 ostr << L" " << it->name << '\n';
446 bool isInvokable() const override final
451 bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
458 else if (in.size() == 1)
460 types::InternalType* _out = nullptr;
461 types::InternalType* arg = in[0];
464 types::String* pString = arg->getAs<types::String>();
465 for (int i = 0; i < pString->getSize(); ++i)
467 if (!extract(pString->get(i), _out))
481 types::Callable::ReturnValue ret;
482 // Overload of extraction needs the BaseAdapter from where we extract
488 ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
490 catch (ast::InternalError & /*se*/)
492 ret = Overload::call(L"%l_e", in, 1, out);
495 // Remove this from "in" to keep "in" unchanged.
499 if (ret == types::Callable::Error)
501 throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
512 } /* namespace view_scilab */
513 } /* namespace org_scilab_modules_scicos */
515 #endif /* BASEADAPTER_HXX_ */