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