Scicos: enforce override and final specifiers
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BaseAdapter.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #ifndef BASEADAPTER_HXX_
14 #define BASEADAPTER_HXX_
15
16 #include <cstring>
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <sstream>
22
23 #include "bool.hxx"
24 #include "double.hxx"
25 #include "user.hxx"
26 #include "int.hxx"
27 #include "internal.hxx"
28 #include "tlist.hxx"
29 #include "mlist.hxx"
30 #include "string.hxx"
31 #include "callable.hxx"
32 #include "overload.hxx"
33 #include "configvariable.hxx"
34 #include "exp.hxx"
35
36 #include "view_scilab/Adapters.hxx"
37 #include "controller_helpers.hxx"
38 #include "utilities.hxx"
39 #include "Controller.hxx"
40 #include "model/BaseObject.hxx"
41
42 extern "C" {
43 #include "localization.h"
44 }
45
46 namespace org_scilab_modules_scicos
47 {
48 namespace view_scilab
49 {
50
51 /**
52  * A property used as a getter/setter for a specific name
53  */
54 template<typename Adaptor>
55 struct property
56 {
57 public:
58     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
59     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
60
61     typedef std::vector< property<Adaptor> > props_t;
62     typedef typename props_t::iterator props_t_it;
63
64
65     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
66     ~property() {};
67
68     size_t original_index;
69     std::wstring name;
70     getter_t get;
71     setter_t set;
72
73     bool operator< (const std::wstring& v) const
74     {
75         return name < v;
76     }
77
78     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
79     {
80         return p1.original_index < p2.original_index;
81     }
82
83     /*
84      * Static properties accessors
85      */
86     static props_t fields;
87
88     /**
89      * @return true if the properties have already been setup, false otherwise.
90      */
91     static bool properties_have_not_been_set()
92     {
93         return fields.empty();
94     }
95
96     /**
97      * Add a property to an Adaptor
98      */
99     static void add_property(const std::wstring& name, getter_t g, setter_t s)
100     {
101         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
102         fields.insert(pos, property(name, g, s));
103     }
104 };
105
106 /**
107  * Base definition of the adapter pattern, implement the get / set dispatch.
108  *
109  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
110  */
111 template<typename Adaptor, typename Adaptee>
112 class BaseAdapter : public types::UserType
113 {
114
115 public:
116     BaseAdapter() : m_adaptee(nullptr) {};
117     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
118     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
119     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
120     {
121         Controller controller;
122         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren, true);
123         m_adaptee = controller.getObject< Adaptee >(id);
124     };
125     ~BaseAdapter()
126     {
127         if (m_adaptee != nullptr)
128         {
129             Controller controller;
130             controller.deleteObject(m_adaptee->id());
131         }
132     };
133
134     /*
135      * property accessors
136      */
137
138     bool hasProperty(const std::wstring& _sKey) const
139     {
140         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
141         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
142     }
143
144     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
145     {
146         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
147         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
148         {
149             return found->get(static_cast<Adaptor*>(this), controller);
150         }
151         return 0;
152     }
153
154     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
155     {
156         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
157         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
158         {
159             return found->set(*static_cast<Adaptor*>(this), v, controller);
160         }
161         return false;
162     }
163
164     /**
165      * property as TList accessors
166      */
167
168     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
169     {
170         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
171         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
172
173         // create the header
174         types::String* header = new types::String(1, 1 + (int)properties.size());
175         header->set(0, Adaptor::getSharedTypeStr().c_str());
176         int index = 1;
177         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
178         {
179             header->set(index, it->name.c_str());
180         }
181         tlist->append(header);
182
183         // set the tlist field value
184         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
185         {
186             types::InternalType* field = it->get(*static_cast<Adaptor*>(this), controller);
187             tlist->append(field);
188             if (field->isList())
189             {
190                 field->killMe();
191             }
192         }
193
194         return tlist;
195     }
196
197     bool setAsTList(types::InternalType* v, Controller& controller)
198     {
199         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
200         {
201             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
202             return false;
203         }
204         types::TList* current = v->getAs<types::TList>();
205         // The input TList cannot be empty
206         if (current->getSize() < 1)
207         {
208             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
209             return false;
210         }
211
212         // Check the header
213         types::String* header = current->getFieldNames();
214         if (header->getSize() < 1)
215         {
216             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);
217             return false;
218         }
219         // Make sure it is the same type as the Adapter
220         if (header->get(0) != Adaptor::getSharedTypeStr())
221         {
222             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());
223             return false;
224         }
225
226         // Retrieve the Adapter's properties
227         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
228
229         // For each input property, if it corresponds to an Adapter's property, set it.
230         for (int index = 1; index < header->getSize(); ++index)
231         {
232             typename property<Adaptor>::props_t_it found = std::lower_bound(properties.begin(), properties.end(), header->get(index));
233             if (found != properties.end() && !(header->get(index) < found->name))
234             {
235                 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
236                 if (!status)
237                 {
238                     return false;
239                 }
240             }
241         }
242
243         return true;
244     }
245
246     /**
247      * property comparison
248      */
249
250     types::Bool* equal(types::UserType*& ut) override final
251     {
252         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
253         // Check that 'ut' is an Adapter of the same type as *this
254         if (adapter_index == Adapters::INVALID_ADAPTER)
255         {
256             return new types::Bool(false);
257         }
258         if (this->getTypeStr() != ut->getTypeStr())
259         {
260             return new types::Bool(false);
261         }
262
263         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
264         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
265
266         types::Bool* ret = new types::Bool(1, 1 + properties.size());
267         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
268
269         Controller controller;
270         int index = 1;
271         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
272         {
273             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
274             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
275             ret->set(index, *ith_prop1 == *ith_prop2);
276
277             // Getting a property allocates data, so free it
278             ith_prop1->killMe();
279             ith_prop2->killMe();
280         }
281
282         return ret;
283     }
284
285     /**
286      * @return the Adaptee
287      */
288     Adaptee* getAdaptee() const
289     {
290         return m_adaptee;
291     }
292
293     /*
294      * All following methods should be implemented by each template instance
295      */
296
297     virtual std::wstring getTypeStr() = 0;
298     virtual std::wstring getShortTypeStr() = 0;
299
300 private:
301     virtual UserType* clone() override final
302     {
303         return new Adaptor(*static_cast<Adaptor*>(this));
304     }
305
306     /*
307      * Implement a specific types::User
308      */
309
310     bool isAssignable() override final
311     {
312         return true;
313     }
314
315     bool extract(const std::wstring & name, types::InternalType *& out) override final
316     {
317         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
318         if (found != property<Adaptor>::fields.end() && !(name < found->name))
319         {
320             Controller controller;
321             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
322             if (value == 0)
323             {
324                 return false;
325             }
326
327             out = value;
328             return true;
329         }
330
331         // specific case : to ease debugging let the user retrieve the model ID
332         if (name == L"modelID")
333         {
334             out = new types::Int64(m_adaptee->id());
335             return true;
336         }
337
338         return false;
339     }
340
341     types::InternalType* extract(types::typed_list* _pArgs) override final
342     {
343         if (_pArgs->size() == 0)
344         {
345             // call overload
346             return NULL;
347         }
348
349         if ((*_pArgs)[0]->isString())
350         {
351             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
352             types::InternalType* pOut = NULL;
353             extract(std::wstring(pStr->get(0)), pOut);
354             return pOut;
355         }
356         else
357         {
358             if ((*_pArgs)[0]->isDouble())
359             {
360                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
361
362                 if (index->get(0) == 1)
363                 {
364                     // When _pArgs is '1', return the list of the property names of the Adaptor
365
366                     // Sort the properties before extracting them
367                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
368                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
369
370                     // Allocate the return
371                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
372
373                     int i = 0;
374                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
375                     {
376                         pOut->set(i, it->name.data());
377                     }
378                     return pOut;
379                 }
380             }
381             else
382             {
383                 // TO DO : management other type for arguments like a scalar or matrix of double
384             }
385         }
386
387         return NULL;
388     }
389
390     types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
391     {
392         for (size_t i = 0; i < _pArgs->size(); i++)
393         {
394             if ((*_pArgs)[i]->isString())
395             {
396                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
397                 std::wstring name = pStr->get(0);
398
399                 Controller controller;
400                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
401                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
402                 {
403                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
404                 }
405
406                 return this;
407             }
408             else
409             {
410                 return NULL;
411             }
412         }
413
414         // call overload
415         return NULL;
416     }
417
418     void whoAmI(void) override
419     {
420         std::cout << "scicos object";
421     }
422
423     bool hasToString() override final
424     {
425         // Do not allow scilab to call toString of this class
426         return false;
427     }
428
429     bool toString(std::wostringstream& ostr) override final
430     {
431         // Deprecated, use the overload instead
432         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
433         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
434
435         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
436         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
437         {
438             ostr << L"  " << it->name << std::endl;
439         }
440         return true;
441     }
442
443     bool isInvokable() const override final
444     {
445         return true;
446     }
447
448     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
449     {
450         if (in.size() == 0)
451         {
452             out.push_back(this);
453             return true;
454         }
455         else if (in.size() == 1)
456         {
457             types::InternalType* _out = nullptr;
458             types::InternalType*  arg = in[0];
459             if (arg->isString())
460             {
461                 types::String* pString = arg->getAs<types::String>();
462                 for (int i = 0; i < pString->getSize(); ++i)
463                 {
464                     if (!extract(pString->get(i), _out))
465                     {
466                         return false;
467                     }
468                     out.push_back(_out);
469                 }
470             }
471
472             if (!out.empty())
473             {
474                 return true;
475             }
476         }
477
478         types::Callable::ReturnValue ret;
479         // Overload of extraction needs the BaseAdapter from where we extract
480         this->IncreaseRef();
481         in.push_back(this);
482
483         try
484         {
485             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
486         }
487         catch (ast::InternalError & /*se*/)
488         {
489             ret = Overload::call(L"%l_e", in, 1, out);
490         }
491
492         // Remove this from "in" to keep "in" unchanged.
493         this->DecreaseRef();
494         in.pop_back();
495
496         if (ret == types::Callable::Error)
497         {
498             throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
499         }
500
501         return true;
502     }
503
504 private:
505     Adaptee* m_adaptee;
506 };
507
508
509 } /* namespace view_scilab */
510 } /* namespace org_scilab_modules_scicos */
511
512 #endif /* BASEADAPTER_HXX_ */