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