Const correctness improvements for Property::Value.
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-value.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/public-api/object/property-value.h>
20
21 // EXTERNAL INCLUDES
22 #include <ostream>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/common/extents.h>
27 #include <dali/public-api/math/angle-axis.h>
28 #include <dali/public-api/math/matrix.h>
29 #include <dali/public-api/math/matrix3.h>
30 #include <dali/public-api/math/quaternion.h>
31 #include <dali/public-api/math/radian.h>
32 #include <dali/public-api/math/rect.h>
33 #include <dali/public-api/math/vector2.h>
34 #include <dali/public-api/math/vector3.h>
35 #include <dali/public-api/math/vector4.h>
36 #include <dali/public-api/object/property-array.h>
37 #include <dali/public-api/object/property-map.h>
38 #include <dali/public-api/object/property-types.h>
39
40 namespace Dali
41 {
42
43 struct Property::Value::Impl
44 {
45   ~Impl()
46   {
47     // Destroy the current object stored in Data union memory.
48     Destroy();
49   }
50
51   Impl(const Impl&) = delete;
52
53   Impl(Impl&&) = delete;
54
55   Impl& operator=(Impl&&) = delete;
56
57   Impl()
58   {
59     static_assert(sizeof(Impl) == 16);
60     static_assert(alignof(Impl) == alignof(Impl*));
61
62     SetType(Property::NONE);
63   }
64
65   Impl(bool booleanValue)
66   {
67     SetType(Property::BOOLEAN);
68     mData.mBool.member = booleanValue;
69   }
70
71   Impl(float floatValue)
72   {
73     SetType(Property::FLOAT);
74     mData.mFloat.member = floatValue;
75   }
76
77   Impl(int32_t integerValue)
78   {
79     SetType(Property::INTEGER);
80     mData.mInt.member = integerValue;
81   }
82
83   Impl(Vector2 vectorValue)
84   {
85     SetType(Property::VECTOR2);
86     ConstructInplace(mData.mVector2.member, std::move(vectorValue));
87   }
88
89   Impl(Vector3 vectorValue)
90   {
91     SetType(Property::VECTOR3);
92     ConstructInplace(mData.mVector3.member, std::move(vectorValue));
93   }
94
95   Impl(Extents extentsValue)
96   {
97     SetType(Property::EXTENTS);
98     ConstructInplace(mData.mExtents.member, std::move(extentsValue));
99   }
100
101   Impl(Property::Map mapValue)
102   {
103     SetType(Property::MAP);
104     ConstructInplace(mData.mMap.member, std::move(mapValue));
105   }
106
107   Impl(Property::Array arrayValue)
108   {
109     SetType(Property::ARRAY);
110     ConstructInplace(mData.mArray.member, std::move(arrayValue));
111   }
112
113   Impl(std::string stringValue)
114   {
115     SetType(Property::STRING);
116     mData.mString.member = new std::string(std::move(stringValue));
117   }
118
119   Impl(Rect<int32_t> rectValue)
120   {
121     SetType(Property::RECTANGLE);
122     mData.mRect.member = new Rect<int32_t>(std::move(rectValue));
123   }
124
125   Impl(Vector4 vectorValue)
126   {
127     SetType(Property::VECTOR4);
128     mData.mVector4.member = new Vector4(std::move(vectorValue));
129   }
130
131   Impl(Matrix3 matrixValue)
132   {
133     SetType(Property::MATRIX3);
134     mData.mMatrix3.member = new Matrix3(std::move(matrixValue));
135   }
136
137   Impl(Matrix matrixValue)
138   {
139     SetType(Property::MATRIX);
140     mData.mMatrix.member = new Matrix(std::move(matrixValue));
141   }
142
143   Impl(AngleAxis angleAxisValue)
144   {
145     SetType(Property::ROTATION);
146     mData.mAngleAxis.member = new AngleAxis(std::move(angleAxisValue));
147   }
148
149   Type GetType() const
150   {
151     return mData.mType.type;
152   }
153
154   bool GetBool() const
155   {
156     return mData.mBool.member;
157   }
158
159   int32_t GetInt() const
160   {
161     return mData.mInt.member;
162   }
163
164   float GetFloat() const
165   {
166     return mData.mFloat.member;
167   }
168
169   const Extents& GetExtents() const
170   {
171     return mData.mExtents.member;
172   }
173
174   const Vector2& GetVector2() const
175   {
176     return mData.mVector2.member;
177   }
178
179   const Vector3& GetVector3() const
180   {
181     return mData.mVector3.member;
182   }
183
184   const Property::Map& GetMap() const
185   {
186     return mData.mMap.member;
187   }
188
189   const Property::Array& GetArray() const
190   {
191     return mData.mArray.member;
192   }
193
194   const Vector4& GetVector4() const
195   {
196     return *(mData.mVector4.member);
197   }
198
199   const Matrix3& GetMatrix3() const
200   {
201     return *(mData.mMatrix3.member);
202   }
203
204   const Matrix& GetMatrix() const
205   {
206     return *(mData.mMatrix.member);
207   }
208
209   const AngleAxis& GetAngleAxis() const
210   {
211     return *(mData.mAngleAxis.member);
212   }
213
214   const std::string& GetString() const
215   {
216     return *(mData.mString.member);
217   }
218
219   const Rect<int32_t>& GetRect() const
220   {
221     return *(mData.mRect.member);
222   }
223
224   Property::Map* GetMapPtr()
225   {
226     return &(mData.mMap.member);
227   }
228
229   Property::Array* GetArrayPtr()
230   {
231     return &(mData.mArray.member);
232   }
233
234   Impl& operator=(const Impl& other)
235   {
236     const bool isSameType = GetType() == other.GetType();
237
238     if(!isSameType)
239     {
240       Destroy();
241       SetType(other.GetType());
242     }
243
244     switch(GetType())
245     {
246       case Property::NONE:
247       {
248         break;
249       }
250       case Property::BOOLEAN:
251       {
252         mData.mBool.member = other.GetBool();
253         break;
254       }
255       case Property::FLOAT:
256       {
257         mData.mFloat.member = other.GetFloat();
258         break;
259       }
260       case Property::INTEGER:
261       {
262         mData.mInt.member = other.GetInt();
263         break;
264       }
265       case Property::EXTENTS:
266       {
267         auto obj = other.GetExtents();
268         ConstructInplace(mData.mExtents.member, std::move(obj));
269         break;
270       }
271       case Property::VECTOR2:
272       {
273         auto obj = other.GetVector2();
274         ConstructInplace(mData.mVector2.member, std::move(obj));
275         break;
276       }
277       case Property::VECTOR3:
278       {
279         auto obj = other.GetVector3();
280         ConstructInplace(mData.mVector3.member, std::move(obj));
281         break;
282       }
283       case Property::ARRAY:
284       {
285         auto obj = other.GetArray();
286         ConstructInplace(mData.mArray.member, std::move(obj));
287         break;
288       }
289       case Property::MAP:
290       {
291         auto obj = other.GetMap();
292         ConstructInplace(mData.mMap.member, std::move(obj));
293         break;
294       }
295       case Property::VECTOR4:
296       {
297         if(isSameType)
298         {
299           *mData.mVector4.member = other.GetVector4();
300         }
301         else
302         {
303           mData.mVector4.member = new Vector4(other.GetVector4());
304         }
305         break;
306       }
307       case Property::MATRIX3:
308       {
309         if(isSameType)
310         {
311           *mData.mMatrix3.member = other.GetMatrix3();
312         }
313         else
314         {
315           mData.mMatrix3.member = new Matrix3(other.GetMatrix3());
316         }
317         break;
318       }
319       case Property::MATRIX:
320       {
321         if(isSameType)
322         {
323           *mData.mMatrix.member = other.GetMatrix();
324         }
325         else
326         {
327           mData.mMatrix.member = new Matrix(other.GetMatrix());
328         }
329         break;
330       }
331       case Property::RECTANGLE:
332       {
333         if(isSameType)
334         {
335           *mData.mRect.member = other.GetRect();
336         }
337         else
338         {
339           mData.mRect.member = new Rect<int32_t>(other.GetRect());
340         }
341         break;
342       }
343       case Property::ROTATION:
344       {
345         if(isSameType)
346         {
347           *mData.mAngleAxis.member = other.GetAngleAxis();
348         }
349         else
350         {
351           mData.mAngleAxis.member = new AngleAxis(other.GetAngleAxis());
352         }
353         break;
354       }
355       case Property::STRING:
356       {
357         if(isSameType)
358         {
359           *mData.mString.member = other.GetString();
360         }
361         else
362         {
363           mData.mString.member = new std::string(other.GetString());
364         }
365         break;
366       }
367     }
368     return *this;
369   }
370
371 private:
372   void SetType(Type typeValue)
373   {
374     mData.mType.type = typeValue;
375   }
376
377   /**
378    * This helper function takes a typed(Tp) memory location( member)
379    * and a object of same type( val ) and move constructs a new object of
380    * same type(Tp) in the memory location( member) using placement new.
381    * after this function call member location will have a object of type Tp.
382    */
383   template<typename Tp>
384   void ConstructInplace(Tp& member, Tp&& val)
385   {
386     new(&member) Tp(std::forward<Tp>(val));
387   }
388
389   /**
390   * Destroy the object created in the Data union memory by probing the
391   * type and calling the appropriate destructor.
392   * and also reset the type and memory location to reflect that .
393   */
394   void Destroy()
395   {
396     switch(GetType())
397     {
398       case Property::NONE:
399       case Property::BOOLEAN:
400       case Property::FLOAT:
401       case Property::INTEGER:
402       {
403         break; // nothing to do
404       }
405       case Property::EXTENTS:
406       {
407         mData.mExtents.member.~Extents();
408         break;
409       }
410       case Property::VECTOR2:
411       {
412         mData.mVector2.member.~Vector2();
413         break;
414       }
415       case Property::VECTOR3:
416       {
417         mData.mVector3.member.~Vector3();
418         break;
419       }
420       case Property::ARRAY:
421       {
422         using array = Property::Array;
423         mData.mArray.member.~array();
424         break;
425       }
426       case Property::MAP:
427       {
428         using map = Property::Map;
429         mData.mMap.member.~map();
430         break;
431       }
432       case Property::VECTOR4:
433       {
434         delete mData.mVector4.member;
435         break;
436       }
437       case Property::MATRIX3:
438       {
439         delete mData.mMatrix3.member;
440         break;
441       }
442       case Property::MATRIX:
443       {
444         delete mData.mMatrix.member;
445         break;
446       }
447       case Property::RECTANGLE:
448       {
449         delete mData.mRect.member;
450         break;
451       }
452       case Property::ROTATION:
453       {
454         delete mData.mAngleAxis.member;
455         break;
456       }
457       case Property::STRING:
458       {
459         delete mData.mString.member;
460         break;
461       }
462     }
463   }
464
465   /*
466    * This wrapper struct is used for
467    * storing Type in every union member
468    * and can acess it from non active member
469    * of the uninon without invoking UB. this is
470    * possible because of CIS(common initial sequence)
471    * http://eel.is/c++draft/class.mem#general-25
472    */
473   template<typename T>
474   struct UnionMember
475   {
476     Type type;
477     T    member;
478   };
479
480   /**
481    * Tagged union implementation.
482    *
483    * This Data union contains non trivial data
484    * types Map and Array, the default constructor
485    * and destructors are deleted by the compiler
486    * so we provided empty constructor and destructor
487    * just to pacify the compiler.
488    * The only job of this union to give a typed memory buffer to the
489    * Impl class which can construct the appropriate object
490    * using placement new.
491    * As Impl class explicitly construct the object and keeps track of the
492    * object it creates and then destroys them in the ~Impl() this will not leak
493    * any memory.
494    */
495   union Data
496   {
497     Data()
498     {
499     }
500     ~Data()
501     {
502     }
503
504     UnionMember<bool>            mBool;
505     UnionMember<int32_t>         mInt;
506     UnionMember<float>           mFloat;
507     UnionMember<Extents>         mExtents;
508     UnionMember<Vector2>         mVector2;
509     UnionMember<Vector3>         mVector3;
510     UnionMember<Property::Map>   mMap;
511     UnionMember<Property::Array> mArray;
512     UnionMember<Vector4*>        mVector4;
513     UnionMember<Matrix3*>        mMatrix3;
514     UnionMember<Matrix*>         mMatrix;
515     UnionMember<AngleAxis*>      mAngleAxis;
516     UnionMember<std::string*>    mString;
517     UnionMember<Rect<int32_t>*>  mRect;
518     struct
519     {
520       Type type;
521     } mType;
522   };
523
524   Data mData;
525 };
526
527 Property::Value::Value()
528 : mImpl(nullptr)
529 {
530 }
531
532 Property::Value::Value(bool booleanValue)
533 : mImpl(new Impl(booleanValue))
534 {
535 }
536
537 Property::Value::Value(float floatValue)
538 : mImpl(new Impl(floatValue))
539 {
540 }
541
542 Property::Value::Value(int32_t integerValue)
543 : mImpl(new Impl(integerValue))
544 {
545 }
546
547 Property::Value::Value(const Vector2& vectorValue)
548 : mImpl(new Impl(vectorValue))
549 {
550 }
551
552 Property::Value::Value(const Vector3& vectorValue)
553 : mImpl(new Impl(vectorValue))
554 {
555 }
556
557 Property::Value::Value(const Vector4& vectorValue)
558 : mImpl(new Impl(vectorValue))
559 {
560 }
561
562 Property::Value::Value(const Matrix3& matrixValue)
563 : mImpl(new Impl(matrixValue))
564 {
565 }
566
567 Property::Value::Value(const Matrix& matrixValue)
568 : mImpl(new Impl(matrixValue))
569 {
570 }
571
572 Property::Value::Value(const Rect<int32_t>& rectValue)
573 : mImpl(new Impl(rectValue))
574 {
575 }
576
577 Property::Value::Value(const Rect<float>& rectValue)
578 : mImpl(new Impl(Vector4(rectValue.x, rectValue.y, rectValue.width, rectValue.height)))
579 {
580 }
581
582 Property::Value::Value(const AngleAxis& angleAxisValue)
583 : mImpl(new Impl(angleAxisValue))
584 {
585 }
586
587 Property::Value::Value(const Quaternion& quaternionValue)
588 {
589   AngleAxis angleAxisValue;
590   quaternionValue.ToAxisAngle(angleAxisValue.axis, angleAxisValue.angle);
591   mImpl = new Impl(std::move(angleAxisValue));
592 }
593
594 Property::Value::Value(std::string stringValue)
595 : mImpl(new Impl(std::move(stringValue)))
596 {
597 }
598
599 Property::Value::Value(const char* stringValue)
600 : mImpl(nullptr)
601 {
602   if(stringValue) // string constructor is undefined with nullptr
603   {
604     mImpl = new Impl(std::string(stringValue));
605   }
606   else
607   {
608     mImpl = new Impl(std::string());
609   }
610 }
611
612 Property::Value::Value(Property::Array arrayValue)
613 : mImpl(new Impl(std::move(arrayValue)))
614 {
615 }
616
617 Property::Value::Value(Property::Map mapValue)
618 : mImpl(new Impl(std::move(mapValue)))
619 {
620 }
621
622 Property::Value::Value(const Extents& extentsValue)
623 : mImpl(new Impl(extentsValue))
624 {
625 }
626
627 Property::Value::Value(const std::initializer_list<KeyValuePair>& values)
628 : mImpl(new Impl(Property::Map(values)))
629 {
630 }
631
632 Property::Value::Value(Type type)
633 : mImpl(nullptr)
634 {
635   switch(type)
636   {
637     case Property::BOOLEAN:
638     {
639       mImpl = new Impl(false);
640       break;
641     }
642     case Property::FLOAT:
643     {
644       mImpl = new Impl(0.f);
645       break;
646     }
647     case Property::INTEGER:
648     {
649       mImpl = new Impl(0);
650       break;
651     }
652     case Property::VECTOR2:
653     {
654       mImpl = new Impl(Vector2::ZERO);
655       break;
656     }
657     case Property::VECTOR3:
658     {
659       mImpl = new Impl(Vector3::ZERO);
660       break;
661     }
662     case Property::VECTOR4:
663     {
664       mImpl = new Impl(Vector4::ZERO);
665       break;
666     }
667     case Property::RECTANGLE:
668     {
669       mImpl = new Impl(Rect<int32_t>());
670       break;
671     }
672     case Property::ROTATION:
673     {
674       mImpl = new Impl(AngleAxis());
675       break;
676     }
677     case Property::STRING:
678     {
679       mImpl = new Impl(std::string());
680       break;
681     }
682     case Property::MATRIX:
683     {
684       mImpl = new Impl(Matrix());
685       break;
686     }
687     case Property::MATRIX3:
688     {
689       mImpl = new Impl(Matrix3());
690       break;
691     }
692     case Property::ARRAY:
693     {
694       mImpl = new Impl(Property::Array());
695       break;
696     }
697     case Property::MAP:
698     {
699       mImpl = new Impl(Property::Map());
700       break;
701     }
702     case Property::EXTENTS:
703     {
704       mImpl = new Impl(Extents());
705       break;
706     }
707     case Property::NONE:
708     {
709       // No need to create an Impl
710       break;
711     }
712   }
713 }
714
715 Property::Value::Value(const Property::Value& value)
716 : mImpl(nullptr)
717 {
718   // reuse assignment operator
719   operator=(value);
720 }
721
722 Property::Value::Value(Property::Value&& value) noexcept
723 : mImpl(value.mImpl)
724 {
725   value.mImpl = nullptr;
726 }
727
728 Property::Value& Property::Value::operator=(const Property::Value& value)
729 {
730   if(this == &value)
731   {
732     // skip self assignment
733     return *this;
734   }
735
736   if(value.mImpl)
737   {
738     if(!mImpl)
739     {
740       mImpl = new Impl();
741     }
742
743     *mImpl = *(value.mImpl);
744   }
745   else
746   {
747     delete mImpl;
748     mImpl = nullptr;
749   }
750
751   return *this;
752 }
753
754 Property::Value& Property::Value::operator=(Property::Value&& value) noexcept
755 {
756   if(this != &value)
757   {
758     delete mImpl;
759     mImpl       = value.mImpl;
760     value.mImpl = nullptr;
761   }
762
763   return *this;
764 }
765
766 Property::Value::~Value()
767 {
768   delete mImpl;
769 }
770
771 Property::Type Property::Value::GetType() const
772 {
773   return mImpl ? mImpl->GetType() : Property::NONE;
774 }
775
776 bool Property::Value::Get(bool& booleanValue) const
777 {
778   bool converted = false;
779   if(mImpl)
780   {
781     if(mImpl->GetType() == BOOLEAN)
782     {
783       booleanValue = mImpl->GetBool();
784       converted    = true;
785     }
786     else if(mImpl->GetType() == INTEGER)
787     {
788       booleanValue = mImpl->GetInt();
789       converted    = true;
790     }
791   }
792   return converted;
793 }
794
795 bool Property::Value::Get(float& floatValue) const
796 {
797   bool converted = false;
798   if(mImpl)
799   {
800     if(mImpl->GetType() == FLOAT)
801     {
802       floatValue = mImpl->GetFloat();
803       converted  = true;
804     }
805     else if(mImpl->GetType() == BOOLEAN)
806     {
807       floatValue = static_cast<float>(mImpl->GetBool());
808       converted  = true;
809     }
810     else if(mImpl->GetType() == INTEGER)
811     {
812       floatValue = static_cast<float>(mImpl->GetInt());
813       converted  = true;
814     }
815   }
816   return converted;
817 }
818
819 bool Property::Value::Get(int32_t& integerValue) const
820 {
821   bool converted = false;
822   if(mImpl)
823   {
824     if(mImpl->GetType() == INTEGER)
825     {
826       integerValue = mImpl->GetInt();
827       converted    = true;
828     }
829     else if(mImpl->GetType() == BOOLEAN)
830     {
831       integerValue = mImpl->GetBool();
832       converted    = true;
833     }
834     else if(mImpl->GetType() == FLOAT)
835     {
836       integerValue = static_cast<int32_t>(mImpl->GetFloat());
837       converted    = true;
838     }
839   }
840   return converted;
841 }
842
843 bool Property::Value::Get(Vector2& vectorValue) const
844 {
845   bool converted = false;
846   if(mImpl)
847   {
848     if(mImpl->GetType() == VECTOR4)
849     {
850       vectorValue = mImpl->GetVector4();
851       converted   = true;
852     }
853     else if(mImpl->GetType() == VECTOR2)
854     {
855       vectorValue = mImpl->GetVector2();
856       converted   = true;
857     }
858     else if(mImpl->GetType() == VECTOR3)
859     {
860       vectorValue = mImpl->GetVector3();
861       converted   = true;
862     }
863   }
864   return converted;
865 }
866
867 bool Property::Value::Get(Vector3& vectorValue) const
868 {
869   bool converted = false;
870   if(mImpl)
871   {
872     if(mImpl->GetType() == VECTOR4)
873     {
874       vectorValue = mImpl->GetVector4();
875       converted   = true;
876     }
877     else if(mImpl->GetType() == VECTOR2)
878     {
879       vectorValue = mImpl->GetVector2();
880       converted   = true;
881     }
882     else if(mImpl->GetType() == VECTOR3)
883     {
884       vectorValue = mImpl->GetVector3();
885       converted   = true;
886     }
887   }
888   return converted;
889 }
890
891 bool Property::Value::Get(Vector4& vectorValue) const
892 {
893   bool converted = false;
894   if(mImpl)
895   {
896     if(mImpl->GetType() == VECTOR4)
897     {
898       vectorValue = mImpl->GetVector4();
899       converted   = true;
900     }
901     else if(mImpl->GetType() == VECTOR2)
902     {
903       vectorValue = mImpl->GetVector2();
904       converted   = true;
905     }
906     else if(mImpl->GetType() == VECTOR3)
907     {
908       vectorValue = mImpl->GetVector3();
909       converted   = true;
910     }
911   }
912   return converted;
913 }
914
915 bool Property::Value::Get(Matrix3& matrixValue) const
916 {
917   bool converted = false;
918   if(mImpl && (mImpl->GetType() == MATRIX3))
919   {
920     matrixValue = mImpl->GetMatrix3();
921     converted   = true;
922   }
923   return converted;
924 }
925
926 bool Property::Value::Get(Matrix& matrixValue) const
927 {
928   bool converted = false;
929   if(mImpl && (mImpl->GetType() == MATRIX))
930   {
931     matrixValue = mImpl->GetMatrix();
932     converted   = true;
933   }
934   return converted;
935 }
936
937 bool Property::Value::Get(Rect<int32_t>& rectValue) const
938 {
939   bool converted = false;
940   if(mImpl && (mImpl->GetType() == RECTANGLE))
941   {
942     rectValue = mImpl->GetRect();
943     converted = true;
944   }
945   return converted;
946 }
947
948 bool Property::Value::Get(AngleAxis& angleAxisValue) const
949 {
950   bool converted = false;
951   if(mImpl && (mImpl->GetType() == ROTATION))
952   {
953     angleAxisValue = mImpl->GetAngleAxis();
954     converted      = true;
955   }
956   return converted;
957 }
958
959 bool Property::Value::Get(Quaternion& quaternionValue) const
960 {
961   bool converted = false;
962   if(mImpl && (mImpl->GetType() == ROTATION))
963   {
964     auto& obj       = mImpl->GetAngleAxis();
965     quaternionValue = Quaternion(obj.angle, obj.axis);
966     converted       = true;
967   }
968   return converted;
969 }
970
971 bool Property::Value::Get(std::string& stringValue) const
972 {
973   bool converted = false;
974   if(mImpl && (mImpl->GetType() == STRING))
975   {
976     stringValue.assign(mImpl->GetString());
977     converted = true;
978   }
979   return converted;
980 }
981
982 bool Property::Value::Get(Property::Array& arrayValue) const
983 {
984   bool converted = false;
985   if(mImpl && (mImpl->GetType() == ARRAY))
986   {
987     arrayValue = mImpl->GetArray();
988     converted  = true;
989   }
990   return converted;
991 }
992
993 bool Property::Value::Get(Property::Map& mapValue) const
994 {
995   bool converted = false;
996   if(mImpl && (mImpl->GetType() == MAP))
997   {
998     mapValue  = mImpl->GetMap();
999     converted = true;
1000   }
1001   return converted;
1002 }
1003
1004 Property::Array const* Property::Value::GetArray() const
1005 {
1006   if(mImpl && (mImpl->GetType() == ARRAY))
1007   {
1008     return mImpl->GetArrayPtr();
1009   }
1010   return nullptr;
1011 }
1012
1013 Property::Array* Property::Value::GetArray()
1014 {
1015   Property::Array* array = nullptr;
1016   if(mImpl && (mImpl->GetType() == ARRAY)) // type cannot change in mImpl so array is allocated
1017   {
1018     array = mImpl->GetArrayPtr();
1019   }
1020   return array;
1021 }
1022
1023 Property::Map const* Property::Value::GetMap() const
1024 {
1025   Property::Map* map = nullptr;
1026   if(mImpl && (mImpl->GetType() == MAP)) // type cannot change in mImpl so map is allocated
1027   {
1028     map = mImpl->GetMapPtr();
1029   }
1030   return map;
1031 }
1032
1033 Property::Map* Property::Value::GetMap()
1034 {
1035   if(mImpl && (mImpl->GetType() == MAP))
1036   {
1037     return mImpl->GetMapPtr();
1038   }
1039   return nullptr;
1040 }
1041
1042 bool Property::Value::Get(Extents& extentsValue) const
1043 {
1044   bool converted = false;
1045   if(mImpl)
1046   {
1047     if(mImpl->GetType() == EXTENTS)
1048     {
1049       extentsValue = mImpl->GetExtents();
1050       converted    = true;
1051     }
1052     else if(mImpl->GetType() == VECTOR4)
1053     {
1054       auto& obj           = mImpl->GetVector4();
1055       extentsValue.start  = static_cast<uint16_t>(obj.x);
1056       extentsValue.end    = static_cast<uint16_t>(obj.y);
1057       extentsValue.top    = static_cast<uint16_t>(obj.z);
1058       extentsValue.bottom = static_cast<uint16_t>(obj.w);
1059       converted           = true;
1060     }
1061   }
1062   return converted;
1063 }
1064
1065 std::ostream& operator<<(std::ostream& stream, const Property::Value& value)
1066 {
1067   if(value.mImpl)
1068   {
1069     auto obj = value.mImpl;
1070
1071     switch(obj->GetType())
1072     {
1073       case Dali::Property::BOOLEAN:
1074       {
1075         stream << obj->GetBool();
1076         break;
1077       }
1078       case Dali::Property::FLOAT:
1079       {
1080         stream << obj->GetFloat();
1081         break;
1082       }
1083       case Dali::Property::INTEGER:
1084       {
1085         stream << obj->GetInt();
1086         break;
1087       }
1088       case Dali::Property::VECTOR2:
1089       {
1090         stream << obj->GetVector2();
1091         break;
1092       }
1093       case Dali::Property::VECTOR3:
1094       {
1095         stream << obj->GetVector3();
1096         break;
1097       }
1098       case Dali::Property::VECTOR4:
1099       {
1100         stream << obj->GetVector4();
1101         break;
1102       }
1103       case Dali::Property::MATRIX3:
1104       {
1105         stream << obj->GetMatrix3();
1106         break;
1107       }
1108       case Dali::Property::MATRIX:
1109       {
1110         stream << obj->GetMatrix();
1111         break;
1112       }
1113       case Dali::Property::RECTANGLE:
1114       {
1115         stream << obj->GetRect();
1116         break;
1117       }
1118       case Dali::Property::ROTATION:
1119       {
1120         stream << obj->GetAngleAxis();
1121         break;
1122       }
1123       case Dali::Property::STRING:
1124       {
1125         stream << obj->GetString();
1126         break;
1127       }
1128       case Dali::Property::ARRAY:
1129       {
1130         stream << obj->GetArray();
1131         break;
1132       }
1133       case Dali::Property::MAP:
1134       {
1135         stream << obj->GetMap();
1136         break;
1137       }
1138       case Dali::Property::EXTENTS:
1139       {
1140         stream << obj->GetExtents();
1141         break;
1142       }
1143       case Dali::Property::NONE:
1144       { // mImpl will be a nullptr, there's no way to get to this case
1145       }
1146     }
1147   }
1148   else
1149   {
1150     stream << "undefined type";
1151   }
1152   return stream;
1153 }
1154
1155 } // namespace Dali