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