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