6db39d7f3550ddf6e062fb42fdc1c816c2795ae7
[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 <sstream>
27
28 #include "bool.hxx"
29 #include "double.hxx"
30 #include "user.hxx"
31 #include "int.hxx"
32 #include "internal.hxx"
33 #include "tlist.hxx"
34 #include "mlist.hxx"
35 #include "string.hxx"
36 #include "callable.hxx"
37 #include "overload.hxx"
38 #include "configvariable.hxx"
39 #include "exp.hxx"
40 #include "types_comparison_eq.hxx"
41
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"
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     int 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             AdapterView update_partial_information;
196             Controller controller;
197
198             Controller::cloned_t mapped;
199             BaseObject* clone = controller.cloneBaseObject(mapped, adapter.getAdaptee(), cloneChildren, true);
200             m_adaptee = static_cast<Adaptee*>(clone);
201         }
202     };
203     BaseAdapter(const BaseAdapter&& adapter) : BaseAdapter(Controller(), adapter.m_adaptee) {}
204     ~BaseAdapter()
205     {
206         if (m_adaptee != nullptr)
207         {
208             AdapterView update_partial_information;
209
210             Controller controller;
211             controller.deleteObject(m_adaptee->id());
212         }
213     };
214
215     /*
216      * property accessors
217      */
218
219     bool hasProperty(const std::wstring& _sKey) const
220     {
221         typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
222         return found != property<Adaptor>::fields.end();
223     }
224
225     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
226     {
227         typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
228         if (found != property<Adaptor>::fields.end())
229         {
230             Adaptor& adapter = *static_cast<Adaptor*>(this);
231             return found->get(adapter, controller);
232         }
233         return nullptr;
234     }
235
236     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
237     {
238         typename property<Adaptor>::props_t_it found = property<Adaptor>::find(_sKey);
239         if (found != property<Adaptor>::fields.end())
240         {
241             Adaptor& adapter = *static_cast<Adaptor*>(this);
242             return found->set(adapter, v, controller);
243         }
244         return false;
245     }
246
247     void copyProperties(const Adaptor& adaptor, Controller controller = Controller())
248     {
249         for (const auto& p : property<Adaptor>::fields)
250         {
251             types::InternalType* pIT = p.get(adaptor, controller);
252             p.set(*static_cast<Adaptor*>(this), pIT, controller);
253             pIT->killMe();
254         }
255     }
256
257     /**
258      * property as TList accessors
259      */
260
261     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
262     {
263         const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
264
265         // create the header
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)
269         {
270             header->set(1 + p.original_index, p.name.c_str());
271
272             types::InternalType* field = p.get(*static_cast<Adaptor*>(this), controller);
273             tlist->set(1 + p.original_index, field);
274             if (field->isList())
275             {
276                 field->killMe();
277             }
278
279         }
280         tlist->set(0, header);
281
282         return tlist;
283     }
284
285     bool setAsTList(types::InternalType* v, Controller& controller)
286     {
287         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
288         {
289             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %ls: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
290             return false;
291         }
292         types::TList* current = v->getAs<types::TList>();
293         // The input TList cannot be empty
294         if (current->getSize() < 1)
295         {
296             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %ls: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
297             return false;
298         }
299
300         // Check the header
301         types::String* header = current->getFieldNames();
302         if (header->getSize() < 1)
303         {
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);
305             return false;
306         }
307         // Make sure it is the same type as the Adapter
308         if (header->get(0) != Adaptor::getSharedTypeStr())
309         {
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());
311             return false;
312         }
313
314         // Retrieve the Adapter's properties
315         const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
316
317         // For each input property, if it corresponds to an Adapter's property, set it.
318         for (int index = 1; index < header->getSize(); ++index)
319         {
320             std::wstring name(header->get(index));
321             typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
322             if (found != properties.end())
323             {
324                 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
325                 if (!status)
326                 {
327                     return false;
328                 }
329             }
330         }
331
332         return true;
333     }
334
335     /**
336      * property comparison
337      */
338
339     bool operator==(const types::InternalType& o) override final
340     {
341
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)
345         {
346             return false;
347         }
348         if (this->getTypeStr() != o.getTypeStr())
349         {
350             return false;
351         }
352
353         const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
354
355         bool internal_equal;
356         Controller controller;
357         for (const auto& p : properties)
358         {
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);
361
362             // loop while the inner types are equals
363             internal_equal = *ith_prop1 == *ith_prop2;
364
365             // Getting a property allocates data, so free it
366             ith_prop1->killMe();
367             ith_prop2->killMe();
368
369             if (!internal_equal)
370             {
371                 return false;
372             }
373         }
374
375         return true;
376     }
377
378     types::Bool* equal(types::UserType*& ut) override final
379     {
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)
383         {
384             return new types::Bool(false);
385         }
386         if (this->getTypeStr() != ut->getTypeStr())
387         {
388             return new types::Bool(false);
389         }
390
391         const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
392
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
395
396         Controller controller;
397         for (const auto& p : properties)
398         {
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);
402
403             // Getting a property allocates data, so free them
404             ith_prop1->killMe();
405             ith_prop2->killMe();
406         }
407
408         return ret;
409     }
410
411     /**
412      * Return a default constructed Scilab value
413      */
414     template<typename T>
415     static types::InternalType* default_value()
416     {
417         T* o = new T();
418         o->IncreaseRef();
419         return o;
420     }
421
422     /**
423      * Increase reference count to store a Scilab value
424      */
425     template<typename T>
426     static T* reference_value(T* o)
427     {
428         o->IncreaseRef();
429         return o;
430     }
431
432
433     /**
434      * @return the Adaptee
435      */
436     Adaptee* getAdaptee() const
437     {
438         return m_adaptee;
439     }
440
441     /*
442      * All following methods should be implemented by each template instance
443      */
444
445     virtual std::wstring getTypeStr() const override = 0;
446     virtual std::wstring getShortTypeStr() const override = 0;
447
448 private:
449     virtual UserType* clone() override final
450     {
451         return new Adaptor(*static_cast<Adaptor*>(this));
452     }
453
454     /*
455      * Implement a specific types::User
456      */
457
458     bool isAssignable() override final
459     {
460         return true;
461     }
462
463     // sb.model.rpar.contrib will return a reference to contrib
464     bool isContainer() override final
465     {
466         return true;
467     }
468
469     bool extract(const std::wstring & name, types::InternalType *& out) override final
470     {
471         typename property<Adaptor>::props_t_it found = property<Adaptor>::find(name);
472         if (found != property<Adaptor>::fields.end())
473         {
474             Controller controller;
475             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
476             if (value == 0)
477             {
478                 return false;
479             }
480
481             out = value;
482             return true;
483         }
484
485         // specific case : to ease debugging let the user retrieve the model ID
486         if (name == L"modelID")
487         {
488             out = new types::Int64(m_adaptee->id());
489             return true;
490         }
491
492         return false;
493     }
494
495     types::InternalType* extract(types::typed_list* _pArgs) override final
496     {
497         if (_pArgs->size() == 0)
498         {
499             // call overload
500             return NULL;
501         }
502
503         if ((*_pArgs)[0]->isString())
504         {
505             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
506             types::InternalType* pOut = NULL;
507             extract(std::wstring(pStr->get(0)), pOut);
508             return pOut;
509         }
510         else
511         {
512             if ((*_pArgs)[0]->isDouble())
513             {
514                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
515
516                 if (index->get(0) == 1)
517                 {
518                     // When _pArgs is '1', return the list of the property names of the Adaptor
519
520                     const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
521
522                     // Allocate the return
523                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
524
525                     for (const auto& p : properties)
526                     {
527                         pOut->set(p.original_index, p.name.data());
528                     }
529                     return pOut;
530                 }
531             }
532             else
533             {
534                 // TO DO : management other type for arguments like a scalar or matrix of double
535             }
536         }
537
538         return NULL;
539     }
540
541     types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
542     {
543         for (size_t i = 0; i < _pArgs->size(); i++)
544         {
545             if ((*_pArgs)[i]->isString())
546             {
547                 Controller controller;
548
549                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
550
551                 Adaptor* work;
552                 if (getAdaptee()->refCount() > 0)
553                 {
554                     // clone()
555                     work = new Adaptor(*static_cast<Adaptor*>(this));
556                 }
557                 else
558                 {
559                     work = static_cast<Adaptor*>(this);
560                 }
561
562                 typename property<Adaptor>::props_t_it found = property<Adaptor>::find(std::wstring(pStr->get(0)));
563                 if (found != property<Adaptor>::fields.end())
564                 {
565                     found->set(*work, _pSource, controller);
566                 }
567
568                 return work;
569             }
570             else
571             {
572                 return NULL;
573             }
574         }
575
576         // call overload
577         return NULL;
578     }
579
580     void whoAmI(void) override
581     {
582         std::cout << "scicos object";
583     }
584
585     bool hasToString() override final
586     {
587         // Do not allow scilab to call toString of this class
588         return false;
589     }
590
591     bool toString(std::wostringstream& ostr) override final
592     {
593         // Deprecated, use the overload instead
594         const typename property<Adaptor>::props_t& properties = property<Adaptor>::fields;
595
596         ostr << L"scicos_" <<  getTypeStr() << L" type :" << '\n';
597         for (const auto& p : properties)
598         {
599             ostr << L"  " << p.name << '\n';
600         }
601         return true;
602     }
603
604     bool isInvokable() const override final
605     {
606         return true;
607     }
608
609     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
610     {
611         if (in.size() == 0)
612         {
613             out.push_back(this);
614             return true;
615         }
616         else if (in.size() == 1)
617         {
618             types::InternalType* _out = nullptr;
619             types::InternalType*  arg = in[0];
620             if (arg->isString())
621             {
622                 types::String* pString = arg->getAs<types::String>();
623                 for (int i = 0; i < pString->getSize(); ++i)
624                 {
625                     if (!extract(pString->get(i), _out))
626                     {
627                         return false;
628                     }
629                     out.push_back(_out);
630                 }
631             }
632
633             if (!out.empty())
634             {
635                 return true;
636             }
637         }
638
639         types::Callable::ReturnValue ret;
640         // Overload of extraction needs the BaseAdapter from where we extract
641         this->IncreaseRef();
642         in.push_back(this);
643
644         try
645         {
646             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
647         }
648         catch (ast::InternalError & /*se*/)
649         {
650             ret = Overload::call(L"%l_e", in, 1, out);
651         }
652
653         // Remove this from "in" to keep "in" unchanged.
654         this->DecreaseRef();
655         in.pop_back();
656
657         if (ret == types::Callable::Error)
658         {
659             throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
660         }
661
662         return true;
663     }
664
665 private:
666     Adaptee* m_adaptee;
667 };
668
669
670 } /* namespace view_scilab */
671 } /* namespace org_scilab_modules_scicos */
672
673 #endif /* BASEADAPTER_HXX_ */