5c387de2969f2f607ec2b472e48b7fbbc38c6782
[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-2014 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #ifndef BASEADAPTER_HXX_
14 #define BASEADAPTER_HXX_
15
16 #include <cstring>
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <sstream>
22
23 #include "bool.hxx"
24 #include "double.hxx"
25 #include "user.hxx"
26 #include "internal.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "string.hxx"
30 #include "callable.hxx"
31 #include "overload.hxx"
32 #include "scilabexception.hxx"
33
34 #include "utilities.hxx"
35 #include "Controller.hxx"
36 #include "Adapters.hxx"
37 #include "model/BaseObject.hxx"
38
39 namespace org_scilab_modules_scicos
40 {
41 namespace view_scilab
42 {
43
44 /**
45  * A property used as a getter/setter for a specific name
46  */
47 template<typename Adaptor>
48 struct property
49 {
50 public:
51     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
52     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
53
54     typedef std::vector< property<Adaptor> > props_t;
55     typedef typename props_t::iterator props_t_it;
56
57
58     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
59     ~property() {};
60
61     size_t original_index;
62     std::wstring name;
63     getter_t get;
64     setter_t set;
65
66     bool operator< (const std::wstring& v) const
67     {
68         return name < v;
69     }
70
71     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
72     {
73         return p1.original_index < p2.original_index;
74     }
75
76     /*
77      * Static properties accessors
78      */
79     static props_t fields;
80
81     /**
82      * @return true if the properties have already been setup, false otherwise.
83      */
84     static bool properties_have_not_been_set()
85     {
86         return fields.empty();
87     }
88
89     /**
90      * Add a property to an Adaptor
91      */
92     static void add_property(const std::wstring& name, getter_t g, setter_t s)
93     {
94         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
95         fields.insert(pos, property(name, g, s));
96     }
97 };
98
99 /**
100  * Base definition of the adapter pattern, implement the get / set dispatch.
101  *
102  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
103  */
104 template<typename Adaptor, typename Adaptee>
105 class BaseAdapter : public types::UserType
106 {
107
108 public:
109     BaseAdapter() : m_adaptee(nullptr) {};
110     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
111     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
112     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
113     {
114         Controller controller;
115         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren);
116         m_adaptee = controller.getObject< Adaptee >(id);
117     };
118     ~BaseAdapter()
119     {
120         if (m_adaptee != nullptr)
121         {
122             Controller controller;
123             controller.deleteObject(m_adaptee->id());
124         }
125     };
126
127     /*
128      * property accessors
129      */
130
131     bool hasProperty(const std::wstring& _sKey) const
132     {
133         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
134         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
135     }
136
137     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
138     {
139         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
140         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
141         {
142             return found->get(static_cast<Adaptor*>(this), controller);
143         }
144         return 0;
145     }
146
147     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
148     {
149         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
150         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
151         {
152             return found->set(*static_cast<Adaptor*>(this), v, controller);
153         }
154         return false;
155     }
156
157     /**
158      * property as TList accessors
159      */
160
161     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
162     {
163         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
164         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
165
166         // create the header
167         types::String* header = new types::String(1, 1 + (int)properties.size());
168         header->set(0, Adaptor::getSharedTypeStr().c_str());
169         int index = 1;
170         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
171         {
172             header->set(index, it->name.c_str());
173         }
174         tlist->append(header);
175
176         // set the tlist field value
177         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
178         {
179             tlist->append(it->get(*static_cast<Adaptor*>(this), controller));
180         }
181
182         return tlist;
183     }
184
185     bool setAsTList(types::InternalType* v, Controller& controller)
186     {
187         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
188         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
189
190         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
191         {
192             return false;
193         }
194         types::TList* current = v->getAs<types::TList>();
195         // The input TList can have fewer elements than the concerned adapter, but not more, and cannot be empty
196         if (current->getSize() > static_cast<int>(1 + properties.size()) || current->getSize() < 1)
197         {
198             return false;
199         }
200
201         // Check the header
202         types::String* header = current->getFieldNames();
203         if (header->getSize() > static_cast<int>(1 + properties.size()) || header->getSize() < 1)
204         {
205             return false;
206         }
207         if (header->get(0) != Adaptor::getSharedTypeStr())
208         {
209             return false;
210         }
211         typename property<Adaptor>::props_t_it it = properties.begin();
212         for (int index = 1; index < header->getSize(); ++index, ++it)
213         {
214             if (header->get(index) != it->name)
215             {
216                 return false;
217             }
218         }
219
220         // This is a valid tlist, get each tlist field value and pass it to the right property decoder
221         it = properties.begin();
222         for (int index = 1; index < header->getSize(); ++index, ++it)
223         {
224             bool status = it->set(*static_cast<Adaptor*>(this), current->get(index), controller);
225             if (!status)
226             {
227                 return false;
228             }
229         }
230
231         return true;
232     }
233
234     /**
235      * property comparison
236      */
237
238     types::Bool* equal(types::UserType*& ut)
239     {
240         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
241         // Check that 'ut' is an Adapter of the same type as *this
242         if (adapter_index == Adapters::INVALID_ADAPTER)
243         {
244             return new types::Bool(false);
245         }
246         if (this->getTypeStr() != ut->getTypeStr())
247         {
248             return new types::Bool(false);
249         }
250
251         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
252         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
253
254         types::Bool* ret = new types::Bool(1, 1 + properties.size());
255         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
256
257         Controller controller = Controller();
258         int index = 1;
259         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
260         {
261             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
262             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
263             ret->set(index, *ith_prop1 == *ith_prop2);
264
265             // Getting a property allocates data, so free it
266             ith_prop1->killMe();
267             ith_prop2->killMe();
268         }
269
270         return ret;
271     }
272
273     /**
274      * @return the Adaptee
275      */
276     Adaptee* getAdaptee() const
277     {
278         return m_adaptee;
279     }
280
281     /*
282      * All following methods should be implemented by each template instance
283      */
284
285     virtual std::wstring getTypeStr() = 0;
286     virtual std::wstring getShortTypeStr() = 0;
287
288 private:
289     types::InternalType* clone()
290     {
291         return new Adaptor(*static_cast<Adaptor*>(this));
292     }
293
294     /*
295      * Implement a specific types::User
296      */
297
298     bool isAssignable()
299     {
300         return true;
301     }
302
303     bool extract(const std::wstring & name, types::InternalType *& out)
304     {
305         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
306         if (found != property<Adaptor>::fields.end() && !(name < found->name))
307         {
308             Controller controller = Controller();
309             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
310             if (value == 0)
311             {
312                 return false;
313             }
314
315             out = value;
316             return true;
317         }
318         return false;
319     }
320
321     types::InternalType* extract(types::typed_list* _pArgs)
322     {
323         if (_pArgs->size() == 0)
324         {
325             // call overload
326             return NULL;
327         }
328
329         if ((*_pArgs)[0]->isString())
330         {
331             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
332             types::InternalType* pOut = NULL;
333             extract(std::wstring(pStr->get(0)), pOut);
334             return pOut;
335         }
336         else
337         {
338             if ((*_pArgs)[0]->isDouble())
339             {
340                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
341
342                 if (index->get(0) == 1)
343                 {
344                     // When _pArgs is '1', return the list of the property names of the Adaptor
345
346                     // Sort the properties before extracting them
347                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
348                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
349
350                     // Allocate the return
351                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
352
353                     int i = 0;
354                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
355                     {
356                         pOut->set(i, it->name.data());
357                     }
358                     return pOut;
359                 }
360             }
361             else
362             {
363                 // TO DO : management other type for arguments like a scalar or matrix of double
364             }
365         }
366
367         return NULL;
368     }
369
370     types::InternalType* insert(types::typed_list* _pArgs, types::InternalType* _pSource)
371     {
372         for (size_t i = 0; i < _pArgs->size(); i++)
373         {
374             if ((*_pArgs)[i]->isString())
375             {
376                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
377                 std::wstring name = pStr->get(0);
378
379                 Controller controller = Controller();
380                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
381                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
382                 {
383                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
384                 }
385
386                 return this;
387             }
388             else
389             {
390                 return NULL;
391             }
392         }
393
394         // call overload
395         return NULL;
396     }
397
398     void whoAmI(void)
399     {
400         std::cout << "scicos object";
401     }
402
403     bool hasToString()
404     {
405         // Do not allow scilab to call toString of this class
406         return false;
407     }
408
409     bool toString(std::wostringstream& ostr)
410     {
411         // Deprecated, use the overload instead
412         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
413         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
414
415         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
416         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
417         {
418             ostr << L"  " << it->name << std::endl;
419         }
420         return true;
421     }
422
423     bool isInvokable() const
424     {
425         return true;
426     }
427
428     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, ast::ConstVisitor & execFunc, const ast::Exp & /*e*/)
429     {
430         if (in.size() == 0)
431         {
432             out.push_back(this);
433             return true;
434         }
435         else if (in.size() == 1)
436         {
437             types::InternalType* _out = nullptr;
438             types::InternalType*  arg = in[0];
439             if (arg->isString())
440             {
441                 types::String* pString = arg->getAs<types::String>();
442                 for (int i = 0; i < pString->getSize(); ++i)
443                 {
444                     if (!extract(pString->get(i), _out))
445                     {
446                         return false;
447                     }
448                     out.push_back(_out);
449                 }
450             }
451
452             if (!out.empty())
453             {
454                 return true;
455             }
456         }
457
458         types::Callable::ReturnValue ret;
459         // Overload of extraction needs the BaseAdapter from where we extract
460         this->IncreaseRef();
461         in.push_back(this);
462
463         try
464         {
465             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out, &execFunc);
466         }
467         catch (ast::ScilabError & /*se*/)
468         {
469             ret = Overload::call(L"%l_e", in, 1, out, &execFunc);
470         }
471
472         // Remove this from "in" to keep "in" unchanged.
473         this->DecreaseRef();
474         in.pop_back();
475
476         if (ret == types::Callable::Error)
477         {
478             throw ast::ScilabError();
479         }
480
481         return true;
482     }
483
484 private:
485     Adaptee* m_adaptee;
486 };
487
488
489 } /* namespace view_scilab */
490 } /* namespace org_scilab_modules_scicos */
491
492 #endif /* BASEADAPTER_HXX_ */