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