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