[AMBClient] - fixed json stream handling
[profile/ivi/automotive-message-broker.git] / lib / abstractpropertytype.h
1 /*
2         Copyright (C) 2012  Intel Corporation
3
4         This library is free software; you can redistribute it and/or
5         modify it under the terms of the GNU Lesser General Public
6         License as published by the Free Software Foundation; either
7         version 2.1 of the License, or (at your option) any later version.
8
9         This library is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12         Lesser General Public License for more details.
13
14         You should have received a copy of the GNU Lesser General Public
15         License along with this library; if not, write to the Free Software
16         Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #ifndef _ABSTRACTPROPERTYTYPE_H_
20 #define _ABSTRACTPROPERTYTYPE_H_
21
22 #include "debugout.h"
23 #include "jsonhelper.h"
24 #include "picojson.h"
25 #include "superptr.hpp"
26 #include "timestamp.h"
27
28 #include <boost/algorithm/string.hpp>
29 #include <boost/any.hpp>
30 #include <boost/lexical_cast.hpp>
31 #include <boost/utility.hpp>
32 #include <iostream>
33 #include <list>
34 #include <memory>
35 #include <string>
36 #include <sstream>
37 #include <stdexcept>
38 #include <type_traits>
39 #include <vector>
40
41 #include <glib.h>
42
43 class Zone {
44
45 public:
46
47         typedef int Type;
48
49         enum {
50                 None = 0,
51                 Front = 1,
52                 Middle = 1 << 1,
53                 Right = 1 << 2,
54                 Left = 1 << 3,
55                 Rear = 1 << 4,
56                 Center = 1 << 5,
57                 LeftSide = 1 << 6,
58                 RightSide = 1 << 7,
59                 FrontSide = 1 << 8,
60                 BackSide = 1 << 9
61         };
62
63 static const Zone::Type FrontRight;
64 static const Zone::Type FrontLeft;
65 static const Zone::Type MiddleRight;
66 static const Zone::Type MiddleLeft;
67 static const Zone::Type RearRight;
68 static const Zone::Type RearLeft;
69
70 typedef std::vector<Zone::Type> ZoneList;
71
72 };
73
74 class AbstractPropertyType
75 {
76 public:
77
78         /*!
79          * \brief The Priority enum describes prority of the property type.
80          */
81         enum Priority
82         {
83                 /*!< normal priority.  This is default */
84                 Normal = 0,
85                 /*!< Low priority. */
86                 Low,
87                 /*!< High priority*/
88                 High,
89                 /*!< Instant.  Using this priority is not thread safe.  This is typically used for
90                  *    Properties that need to be deterministic.
91                  */
92                 Instant
93         };
94
95         AbstractPropertyType(std::string property)
96                 : name(property), timestamp(amb::currentTime()), sequence(-1), zone(Zone::None), priority(Normal)
97         {
98
99         }
100
101         virtual ~AbstractPropertyType()
102         {
103                 for(auto i : destroyed)
104                 {
105                         if(i) i(this);
106                 }
107         }
108
109         /*!
110          * \brief toJson convert this type to json representation.
111          * The json typically looks something like this:
112          * \code
113          * {
114          *  "name" : "VehicleSpeed",
115          *  "type" : "UInt16",
116          *  "source" : "daf23v32342ddsdffafaeefe",
117          *  "zone" : 0,
118          *  "value" : 25
119          * }
120          * \endcode
121          * \return json value representing the type
122          */
123         virtual const picojson::value toJson();
124
125         /*!
126          * \brief fromJson instantiate this type from json
127          * \param json
128          */
129         virtual void fromJson(const picojson::value & json);
130
131         /*!
132          * \brief toString
133          * \return strigified value
134          */
135         virtual std::string toString() const = 0;
136
137         /*!
138          * \brief fromString converts from string value
139          */
140         virtual void fromString(std::string) = 0;
141
142         /*!
143          * \brief toVariant
144          * \return GVariant representation of value. Caller must unref the returned GVariant
145          */
146         virtual GVariant* toVariant() = 0;
147
148         /*!
149          * \brief fromVariant converts GVariant value into compatible native value.  Caller owns
150          * GVariant argument.
151          */
152         virtual void fromVariant(GVariant*) = 0;
153
154         /*!
155          * \brief copy
156          * \return a copy of the AbstractPropertyType
157          */
158         virtual AbstractPropertyType* copy() = 0;
159
160         /*!
161          * \brief quickCopy is intended as a way to quickly copy the often changing bits from one abstract property to another
162          * It assumes that the properties are almost identical in name, source, and zone.
163          * \param other the property to copy from
164          */
165         virtual void quickCopy(AbstractPropertyType* other)
166         {
167                 sequence = other->sequence;
168                 mValue = other->anyValue();
169                 timestamp = other->timestamp;
170         }
171
172         bool operator == (AbstractPropertyType &other)
173         {
174                 std::string one = toString();
175                 std::string two = other.toString();
176                 return one == two
177                                 && zone == other.zone
178                                 && sourceUuid == other.sourceUuid
179                                 && name == other.name;
180         }
181
182         bool operator != (AbstractPropertyType &other)
183         {
184                 std::string one = toString();
185                 std::string two = other.toString();
186                 return one != two;
187         }
188
189         /*!
190          * \brief name Property name. \see VehicleProperty for built-in supported property names
191          */
192         std::string name;
193
194         /*!
195          * \brief alias alias for the property name
196          * \return alias if any of name if alias has not been set
197          */
198         const std::string alias() { return mAlias.empty() ? name : mAlias; }
199
200         void setAlias(const std::string & a) { mAlias = a; }
201
202         /*!
203          * \brief timestamp.  Timestamp when the value was last updated by the system. This is updated automatically
204          * any time setValue() is called
205          * \see amb::currentTime()
206          * \see setValue()
207          */
208         double timestamp;
209
210         /*!
211          * \brief sequence internal counter.  Useful as a unique indentifier.  values is -1 if not used (default).
212          */
213         int32_t sequence;
214
215         /*!
216          * \brief sourceUuid  uuid of the source that produced this property.  This is set by the routingengine
217          * if left unmodified.
218          */
219         std::string sourceUuid;
220
221         /*!
222          * \brief zone that the property is situated in.
223          */
224         Zone::Type zone;
225
226         /*!
227          * \brief priority is used to tell the routing engine how to prioritize routing the value to plugins.
228          * setting this value to AbstractPropertyType::Instant will tell the routing engine to immedietly
229          * route the value without any reliance on the mainloop.  Instant priority is NOT thread safe.
230          * Default priority is AbstractPropertyType::Normal.
231          */
232         Priority priority;
233
234         /*!
235          * \brief setValue
236          * \param val boost::any value.  NOTE: boost::any does not accept type coercion.  Types must match exactly
237          * with native type. (ie, don't use "int" if the native type is "uint")
238          */
239         virtual void setValue(boost::any val)
240         {
241                 mValue = val;
242                 timestamp = amb::currentTime();
243         }
244
245         /*!
246          * \brief value() native value.  Does not use type coercion.  Will throw if types do not match.
247          */
248         template <typename T>
249         T value() const
250         {
251                 return boost::any_cast<T>(mValue);
252         }
253
254         /*!
255          * \brief anyValue
256          * \return boost::any value
257          */
258         boost::any anyValue()
259         {
260                 return mValue;
261         }
262
263         /*!
264          * \brief signature
265          * \return gvariant signature
266          */
267         virtual const string signature()
268         {
269                 auto var = amb::make_super(toVariant());
270                 if(!var) return "";
271
272                 const string s = g_variant_get_type_string(var.get());
273                 return s;
274         }
275
276         /*!
277          * \brief destroyed is called if this property is destroyed.
278          */
279         std::vector<std::function<void(AbstractPropertyType*)>> destroyed;
280
281 protected:
282
283         boost::any mValue;
284
285         std::string mAlias;
286 };
287
288 namespace amb
289 {
290
291 struct PropertyCompare
292 {
293         bool operator()(AbstractPropertyType* const & lhs, AbstractPropertyType* & rhs) const
294         {
295                 if (lhs->name == rhs->name
296                                 && lhs->sourceUuid == rhs->sourceUuid
297                                 && lhs->zone == rhs->zone)
298                 {
299                         return true;
300                 }
301
302                 return false;
303         }
304
305 };
306
307 }
308
309
310 class JsonNumber
311 {
312 public:
313         static double fromJson(picojson::value v)
314         {
315                 return v.get<double>();
316         }
317
318         static picojson::value toJson(double v)
319         {
320                 return picojson::value(v);
321         }
322 };
323
324 class JsonBoolean
325 {
326 public:
327         static bool fromJson(picojson::value v)
328         {
329                 return v.get<bool>();
330         }
331
332         static picojson::value toJson(bool v)
333         {
334                 return picojson::value(v);
335         }
336 };
337
338 class JsonString
339 {
340 public:
341         static std::string fromJson(picojson::value v)
342         {
343                 return v.get<std::string>();
344         }
345
346         static picojson::value toJson(std::string v)
347         {
348                 return picojson::value(v);
349         }
350 };
351
352
353 template <typename T>
354 class BaseGVS
355 {
356 public:
357         static T gvalue(T t)
358         {
359                 return t;
360         }
361 };
362
363 template <typename T>
364 class GVS;
365
366 template <>
367 class GVS<int> : public BaseGVS<int>, public JsonNumber
368 {
369 public:
370         static const char* signature() { return "i"; }
371
372         static int value(GVariant* v)
373         {
374                 int val = 0;
375                 g_variant_get(v, signature(), &val);
376                 return val;
377         }
378
379         static std::string stringize(std::string v)
380         {
381                 return v;
382         }
383 };
384
385 template <>
386 class GVS<double> : public BaseGVS<double>, public JsonNumber
387 {
388 public:
389         static const char* signature() { return "d"; }
390
391         static double value(GVariant* v)
392         {
393                 return g_variant_get_double(v);
394         }
395         static std::string stringize(std::string v)
396         {
397                 return v;
398         }
399 };
400
401 template <>
402 class GVS<uint16_t> : public BaseGVS<uint16_t>, public JsonNumber
403 {
404 public:
405         static const char* signature() { return "q"; }
406
407         static uint16_t value(GVariant* v)
408         {
409                 return g_variant_get_uint16(v);
410         }
411         static std::string stringize(std::string v)
412         {
413                 return v;
414         }
415 };
416
417 template <>
418 class GVS<int16_t> : public BaseGVS<int16_t>, public JsonNumber
419 {
420 public:
421         static const char* signature() { return "n"; }
422
423         static int16_t value(GVariant* v)
424         {
425                 return g_variant_get_int16(v);
426         }
427         static std::string stringize(std::string v)
428         {
429                 return v;
430         }
431 };
432
433 template <>
434 class GVS<char> : public BaseGVS<char>, public JsonNumber
435 {
436 public:
437         static const char* signature() { return "y"; }
438
439         static char value(GVariant* v)
440         {
441                 return g_variant_get_byte(v);
442         }
443         static std::string stringize(std::string v)
444         {
445                 return v;
446         }
447 };
448
449 template <>
450 class GVS<uint32_t> : public BaseGVS<uint32_t>, public JsonNumber
451 {
452 public:
453         static const char* signature() { return "u"; }
454
455         static uint32_t value(GVariant* v)
456         {
457                 return g_variant_get_uint32(v);
458         }
459         static std::string stringize(std::string v)
460         {
461                 return v;
462         }
463 };
464
465 template <>
466 class GVS<int64_t> : public BaseGVS<int64_t>, public JsonNumber
467 {
468 public:
469         static const char* signature() { return "x"; }
470
471         static int64_t value(GVariant* v)
472         {
473                 return g_variant_get_int64(v);
474         }
475         static std::string stringize(std::string v)
476         {
477                 return v;
478         }
479 };
480
481 template <>
482 class GVS<uint64_t> : public BaseGVS<uint64_t>, public JsonNumber
483 {
484 public:
485         static const char* signature() { return "t"; }
486
487         static uint64_t value(GVariant* v)
488         {
489                 return g_variant_get_uint64(v);
490         }
491         static std::string stringize(std::string v)
492         {
493                 return v;
494         }
495 };
496
497 template <>
498 class GVS<bool> : public BaseGVS<bool>, public JsonBoolean
499 {
500 public:
501         static const char* signature() { return "b"; }
502
503         static bool value(GVariant *v)
504         {
505                 return g_variant_get_boolean(v);
506         }
507         static std::string stringize(std::string v)
508         {
509                 if(v == "0" || v == "1")
510                         return v;
511
512                 boost::algorithm::to_lower(v);
513                 return v == "true" ? "1":"0";
514         }
515 };
516
517 template <>
518 class GVS<std::string> : public JsonString
519 {
520 public:
521         static const char* signature() { return "s"; }
522
523         static const char* value(GVariant *v)
524         {
525                 return g_variant_get_string(v, nullptr);
526         }
527         static std::string stringize(std::string v)
528         {
529                 return v;
530         }
531         static const char* gvalue(std::string v)
532         {
533                 return v.c_str();
534         }
535 };
536
537 /*!
538  * \brief BasicPropertyType is a typed property type.  Most internal types are derived from this class
539  * \example
540  * std::unique_ptr<BasicPropertyType<int>> boostPSI = new BasicPropertyType<int>("BoostPSI",5);
541  * boostPSI->priority = AbstractPropertyType::Instant; //set instant because we clean up right after.
542  * routingEngine->updateProperty(boostPSI.get(), sourceUuid());
543  */
544 template <typename T>
545 class BasicPropertyType: public AbstractPropertyType
546 {
547 public:
548         BasicPropertyType(): AbstractPropertyType("")
549         {
550                 mValue = T();
551         }
552
553         BasicPropertyType(BasicPropertyType const & other)
554                 :AbstractPropertyType(other.name)
555         {
556                 setValue(other.value<T>());
557                 timestamp = other.timestamp;
558                 sequence = other.sequence;
559                 sourceUuid = other.sourceUuid;
560                 name = other.name;
561                 zone = other.zone;
562
563         }
564
565         BasicPropertyType & operator = (BasicPropertyType const & other)
566         {
567                 setValue(other.value<T>());
568                 timestamp = other.timestamp;
569                 sequence = other.sequence;
570                 sourceUuid = other.sourceUuid;
571                 name = other.name;
572                 zone = other.zone;
573
574                 return *this;
575         }
576
577         BasicPropertyType & operator = (T const & other)
578         {
579                 setValue(other);
580                 return *this;
581         }
582
583         BasicPropertyType & operator ++ ()
584         {
585                 setValue(basicValue() + 1);
586         }
587
588         BasicPropertyType & operator -- ()
589         {
590                 setValue(basicValue() - 1);
591         }
592
593         bool operator < (const BasicPropertyType<T>& other) const
594         {
595                 return value<T>() < other.value<T>();
596         }
597
598         bool operator > (const BasicPropertyType<T>& other) const
599         {
600                 return value<T>() > other.value<T>();
601         }
602
603         BasicPropertyType( T val)
604                 :AbstractPropertyType("")
605         {
606                 setValue(val);
607         }
608
609         BasicPropertyType( std::string propertyName, T val)
610                 :AbstractPropertyType(propertyName)
611         {
612                 setValue(val);
613         }
614
615         BasicPropertyType( std::string propertyName, std::string val)
616                 :AbstractPropertyType(propertyName)
617         {
618                 if(!val.empty() && val != "")
619                 {
620                         serialize<T>(val);
621                 }
622                 else setValue(T());
623         }
624
625         BasicPropertyType(std::string propertyName)
626                 :AbstractPropertyType(propertyName)
627         {
628                 mValue = T();
629         }
630
631         AbstractPropertyType* copy()
632         {
633                 return new BasicPropertyType<T>(*this);
634         }
635
636         const picojson::value toJson()
637         {
638                 picojson::value v = AbstractPropertyType::toJson();
639
640                 picojson::object object = v.get<picojson::object>();
641
642                 object["value"] = amb::gvariantToJson(toVariant());
643
644                 return picojson::value(object);
645         }
646
647         virtual void fromJson(const picojson::value &json)
648         {
649                 AbstractPropertyType::fromJson(json);
650
651                 fromVariant(amb::jsonToGVariant(json.get("value"), signature()));
652         }
653
654         void fromString(std::string val)
655         {
656                 if(!val.empty() && val != "")
657                 {
658                         serialize<T>(val);
659                 }
660         }
661
662         std::string toString() const
663         {
664                 std::stringstream stream;
665                 stream.precision(10);
666                 stream<<value<T>();
667
668                 return stream.str();
669         }
670
671         GVariant* toVariant()
672         {
673                 return serializeVariant<T>(value<T>());
674         }
675
676         void fromVariant(GVariant *v)
677         {
678                 setValue(deserializeVariant<T>(v));
679         }
680
681         /*!
682          * \brief basicValue
683          * \return Typed version of value.  Slightly more useful than \see AbstractPropertyType::value()
684          */
685
686         T basicValue()
687         {
688                 return value<T>();
689         }
690
691         void setValue(T val)
692         {
693                 AbstractPropertyType::setValue(val);
694         }
695
696         void setValue(boost::any val)
697         {
698                 AbstractPropertyType::setValue(val);
699         }
700
701 private:
702
703         template <class N>
704         void serialize(const std::string & val,  typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
705         {
706                 int someTemp;
707
708                 std::stringstream stream(val);
709
710                 stream>>someTemp;
711                 setValue((N)someTemp);
712         }
713
714         template <class N>
715         void serialize(const std::string & val,  typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
716         {
717                 std::stringstream stream(GVS<T>::stringize(val));
718                 N someTemp;
719                 stream>>someTemp;
720                 setValue(someTemp);
721         }
722
723         template <class N>
724         GVariant* serializeVariant(const T val, typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
725         {
726                 return (g_variant_new("i",(int)val));
727         }
728
729         template <class N>
730         GVariant* serializeVariant(const T val, typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
731         {
732                 return g_variant_new(GVS<T>::signature(),val);
733         }
734
735         template <class N>
736         T deserializeVariant(GVariant* v, typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
737         {
738                 return (T)GVS<int>::value(v);
739         }
740
741         template <class N>
742         T deserializeVariant(GVariant* v, typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
743         {
744                 return GVS<T>::value(v);
745         }
746 };
747
748 class StringPropertyType: public AbstractPropertyType
749 {
750 public:
751
752
753         StringPropertyType()
754                 :AbstractPropertyType("")
755         {
756                 setValue(std::string());
757         }
758
759         StringPropertyType(std::string propertyName)
760                 :AbstractPropertyType(propertyName)
761         {
762                 setValue(std::string());
763         }
764
765         StringPropertyType(std::string propertyName, std::string val)
766                 :AbstractPropertyType(propertyName)
767         {
768                 setValue(val);
769         }
770
771         StringPropertyType(StringPropertyType const & other)
772         :AbstractPropertyType(other.name)
773         {
774                 setValue(other.value<std::string>());
775                 timestamp = other.timestamp;
776                 sequence = other.sequence;
777                 sourceUuid = other.sourceUuid;
778                 name = other.name;
779                 zone = other.zone;
780         }
781
782         StringPropertyType & operator = (StringPropertyType const & other)
783         {
784                 setValue(other.value<std::string>());
785                 timestamp = other.timestamp;
786                 sequence = other.sequence;
787                 sourceUuid = other.sourceUuid;
788                 name = other.name;
789                 zone = other.zone;
790
791                 return *this;
792         }
793
794         StringPropertyType & operator = (std::string const & other)
795         {
796                 setValue(std::string(other));
797                 return *this;
798         }
799
800         bool operator < (const StringPropertyType& other) const
801         {
802                 return value<std::string>() < other.value<std::string>();
803         }
804
805         virtual const picojson::value toJson()
806         {
807                 auto val = AbstractPropertyType::toJson();
808
809                 picojson::object obj = val.get<picojson::object>();
810
811                 obj["value"] = amb::gvariantToJson(toVariant());
812         }
813
814         virtual void fromJson(const picojson::value &json)
815         {
816                 AbstractPropertyType::fromJson(json);
817
818                 fromString(json.get("value").to_str());
819         }
820
821         void fromString(std::string val)
822         {
823                 setValue(val);
824         }
825
826         AbstractPropertyType* copy()
827         {
828                 return new StringPropertyType(*this);
829         }
830
831         std::string toString() const
832         {
833                 return value<std::string>();
834         }
835
836         GVariant* toVariant()
837         {
838                 //mVariant = Glib::Variant<std::string>::create(toString());
839
840                 return g_variant_new_string(toString().c_str());
841
842         }
843
844         void fromVariant(GVariant *v)
845         {
846                 setValue(std::string(g_variant_get_string(v,NULL)));
847         }
848 };
849
850 /*!
851  * \brief ListPropertyType is a AbstractPropertyType for arrays of AbstractPropertyTypes
852  */
853 template <class T>
854 class ListPropertyType: public AbstractPropertyType
855 {
856 public:
857
858         ListPropertyType(std::string propertyName)
859                 : AbstractPropertyType(propertyName), initialized(false)
860         {
861
862         }
863
864         ListPropertyType(std::string propertyName, T value)
865                 : AbstractPropertyType(propertyName), initialized(false)
866         {
867                 appendPriv(value);
868         }
869
870         ListPropertyType(ListPropertyType & other)
871                 :AbstractPropertyType(other.name),initialized(false)
872         {
873                 std::vector<T> l = other.list();
874                 for(auto i : l)
875                 {
876                         append(i);
877                 }
878
879                 timestamp = other.timestamp;
880                 sequence = other.sequence;
881                 sourceUuid = other.sourceUuid;
882                 name = other.name;
883                 zone = other.zone;
884         }
885
886         ~ListPropertyType()
887         {
888                 clear();
889         }
890
891         /*! \brief append - appends a property to the list
892          * \arg property - property to be appended.
893          **/
894         void append(T property)
895         {
896                 if(!initialized)
897                 {
898                         mList.clear();
899                         initialized = true;
900                 }
901
902                 appendPriv(property);
903         }
904
905         uint count()
906         {
907                 return mList.size();
908         }
909
910         AbstractPropertyType* copy()
911         {
912                 return new ListPropertyType(*this);
913         }
914
915         void quickCopy(AbstractPropertyType* other)
916         {
917                 AbstractPropertyType::quickCopy(other);
918                 ListPropertyType<T>* v = static_cast<ListPropertyType<T>*>(other);
919                 if(!v)
920                 {
921                         DebugOut(DebugOut::Error) << "ListPropertyType Quick Copy failed" << endl;
922                         return;
923                 }
924                 mList = v->list();
925         }
926
927         std::string toString() const
928         {
929                 picojson::array array;
930
931                 for(auto i : mList)
932                 {
933                         array.push_back(GVS<T>::toJson(i));
934                 }
935
936                 return picojson::value(array).serialize();
937         }
938
939
940         void fromString(std::string str)
941         {
942                 picojson::value value;
943                 picojson::parse(value, str);
944
945                 picojson::array array = value.get<picojson::array>();
946
947                 for(auto i : array)
948                 {
949                         mList.push_back(GVS<T>::fromJson(i));
950                 }
951
952                 timestamp = amb::currentTime();
953         }
954
955
956         GVariant* toVariant()
957         {
958                 GVariantBuilder params;
959                 g_variant_builder_init(&params, ((const GVariantType *) "av"));
960
961                 for(auto itr : mList)
962                 {
963                         DebugOut(0) << "toVariant value: " << GVS<T>::gvalue(itr) << endl;
964                         GVariant *newvar = g_variant_new("v", g_variant_new(GVS<T>::signature(), GVS<T>::gvalue(itr)));
965                         g_variant_builder_add_value(&params, newvar);
966                 }
967
968                 GVariant* var =  g_variant_builder_end(&params);
969                 g_assert(var);
970                 return var;
971
972         }
973
974         void fromVariant(GVariant* v)
975         {
976                 clear();
977
978                 /// TODO: fill this in
979                 gsize dictsize = g_variant_n_children(v);
980                 for (int i=0;i<dictsize;i++)
981                 {
982                         GVariant *childvariant = g_variant_get_child_value(v,i);
983                         GVariant *innervariant = g_variant_get_variant(childvariant);
984                         appendPriv(GVS<T>::value(innervariant));
985                 }
986         }
987
988         std::vector<T> list() { return mList; }
989
990 private:
991
992         void clear()
993         {
994                 mList.clear();
995         }
996
997         void appendPriv(T i)
998         {
999                 mList.push_back(i);
1000         }
1001
1002         bool initialized;
1003
1004         std::vector<T> mList;
1005 };
1006
1007 #endif