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