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