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