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