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