Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-value.cpp
1 /*
2  * Copyright (c) 2021 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   void SetType(Type typeValue)
425   {
426     mData.mType.type = typeValue;
427   }
428
429 private:
430   /**
431    * This helper function takes a typed(Tp) memory location( member)
432    * and a object of same type( val ) and move constructs a new object of
433    * same type(Tp) in the memory location( member) using placement new.
434    * after this function call member location will have a object of type Tp.
435    */
436   template<typename Tp>
437   void ConstructInplace(Tp& member, Tp&& val)
438   {
439     new(&member) Tp(std::forward<Tp>(val));
440   }
441
442   /**
443   * Destroy the object created in the Data union memory by probing the
444   * type and calling the appropriate destructor.
445   * and also reset the type and memory location to reflect that .
446   */
447   void Destroy()
448   {
449     switch(GetType())
450     {
451       case Property::NONE:
452       case Property::BOOLEAN:
453       case Property::FLOAT:
454       case Property::INTEGER:
455       {
456         break; // nothing to do
457       }
458       case Property::EXTENTS:
459       {
460         mData.mExtents.member.~Extents();
461         break;
462       }
463       case Property::VECTOR2:
464       {
465         mData.mVector2.member.~Vector2();
466         break;
467       }
468       case Property::VECTOR3:
469       {
470         mData.mVector3.member.~Vector3();
471         break;
472       }
473       case Property::ARRAY:
474       {
475         using array = Property::Array;
476         mData.mArray.member.~array();
477         break;
478       }
479       case Property::MAP:
480       {
481         using map = Property::Map;
482         mData.mMap.member.~map();
483         break;
484       }
485       case Property::VECTOR4:
486       {
487         delete mData.mVector4.member;
488         break;
489       }
490       case Property::MATRIX3:
491       {
492         delete mData.mMatrix3.member;
493         break;
494       }
495       case Property::MATRIX:
496       {
497         delete mData.mMatrix.member;
498         break;
499       }
500       case Property::RECTANGLE:
501       {
502         delete mData.mRect.member;
503         break;
504       }
505       case Property::ROTATION:
506       {
507         delete mData.mAngleAxis.member;
508         break;
509       }
510       case Property::STRING:
511       {
512         delete mData.mString.member;
513         break;
514       }
515     }
516   }
517
518   /*
519    * This wrapper struct is used for
520    * storing Type in every union member
521    * and can acess it from non active member
522    * of the uninon without invoking UB. this is
523    * possible because of CIS(common initial sequence)
524    * http://eel.is/c++draft/class.mem#general-25
525    */
526   template<typename T>
527   struct UnionMember
528   {
529     Type type;
530     T    member;
531   };
532
533   /**
534    * Tagged union implementation.
535    *
536    * This Data union contains non trivial data
537    * types Map and Array, the default constructor
538    * and destructors are deleted by the compiler
539    * so we provided empty constructor and destructor
540    * just to pacify the compiler.
541    * The only job of this union to give a typed memory buffer to the
542    * Impl class which can construct the appropriate object
543    * using placement new.
544    * As Impl class explicitly construct the object and keeps track of the
545    * object it creates and then destroys them in the ~Impl() this will not leak
546    * any memory.
547    */
548   union Data
549   {
550     Data()
551     {
552     }
553     ~Data()
554     {
555     }
556
557     UnionMember<bool>            mBool;
558     UnionMember<int32_t>         mInt;
559     UnionMember<float>           mFloat;
560     UnionMember<Extents>         mExtents;
561     UnionMember<Vector2>         mVector2;
562     UnionMember<Vector3>         mVector3;
563     UnionMember<Property::Map>   mMap;
564     UnionMember<Property::Array> mArray;
565     UnionMember<Vector4*>        mVector4;
566     UnionMember<Matrix3*>        mMatrix3;
567     UnionMember<Matrix*>         mMatrix;
568     UnionMember<AngleAxis*>      mAngleAxis;
569     UnionMember<std::string*>    mString;
570     UnionMember<Rect<int32_t>*>  mRect;
571     struct
572     {
573       Type type;
574     } mType;
575   };
576
577   Data mData;
578 };
579
580 /*
581  * Safe way to read an already constructed Object from a buffer.
582  */
583 const Property::Value::Impl& Property::Value::Read() const
584 {
585   return *(std::launder(reinterpret_cast<const Property::Value::Impl*>(mStorage.buffer)));
586 }
587
588 Property::Value::Impl& Property::Value::Write()
589 {
590   return *(std::launder(reinterpret_cast<Property::Value::Impl*>(mStorage.buffer)));
591 }
592
593 Property::Value::Value()
594 {
595   Impl::New(mStorage);
596
597   static_assert(sizeof(Value) == 16);
598   static_assert(alignof(Value) == alignof(Value*));
599 }
600
601 Property::Value::Value(bool booleanValue)
602 {
603   Impl::New(mStorage, booleanValue);
604 }
605
606 Property::Value::Value(float floatValue)
607 {
608   Impl::New(mStorage, floatValue);
609 }
610
611 Property::Value::Value(int32_t integerValue)
612 {
613   Impl::New(mStorage, integerValue);
614 }
615
616 Property::Value::Value(const Vector2& vectorValue)
617 {
618   Impl::New(mStorage, vectorValue);
619 }
620
621 Property::Value::Value(const Vector3& vectorValue)
622 {
623   Impl::New(mStorage, vectorValue);
624 }
625
626 Property::Value::Value(const Vector4& vectorValue)
627 {
628   Impl::New(mStorage, vectorValue);
629 }
630
631 Property::Value::Value(const Matrix3& matrixValue)
632 {
633   Impl::New(mStorage, matrixValue);
634 }
635
636 Property::Value::Value(const Matrix& matrixValue)
637 {
638   Impl::New(mStorage, matrixValue);
639 }
640
641 Property::Value::Value(const Rect<int32_t>& rectValue)
642 {
643   Impl::New(mStorage, rectValue);
644 }
645
646 Property::Value::Value(const Rect<float>& rectValue)
647 {
648   Impl::New(mStorage, Vector4(rectValue.x, rectValue.y, rectValue.width, rectValue.height));
649 }
650
651 Property::Value::Value(const AngleAxis& angleAxisValue)
652 {
653   Impl::New(mStorage, angleAxisValue);
654 }
655
656 Property::Value::Value(const Quaternion& quaternionValue)
657 {
658   AngleAxis angleAxisValue;
659   quaternionValue.ToAxisAngle(angleAxisValue.axis, angleAxisValue.angle);
660   Impl::New(mStorage, std::move(angleAxisValue));
661 }
662
663 Property::Value::Value(std::string stringValue)
664 {
665   Impl::New(mStorage, std::move(stringValue));
666 }
667
668 Property::Value::Value(const char* stringValue)
669 {
670   if(stringValue) // string constructor is undefined with nullptr
671   {
672     Impl::New(mStorage, std::string(stringValue));
673   }
674   else
675   {
676     Impl::New(mStorage, std::string());
677   }
678 }
679
680 Property::Value::Value(Property::Array arrayValue)
681 {
682   Impl::New(mStorage, std::move(arrayValue));
683 }
684
685 Property::Value::Value(Property::Map mapValue)
686 {
687   Impl::New(mStorage, std::move(mapValue));
688 }
689
690 Property::Value::Value(const Extents& extentsValue)
691 {
692   Impl::New(mStorage, extentsValue);
693 }
694
695 Property::Value::Value(const std::initializer_list<KeyValuePair>& values)
696 {
697   Impl::New(mStorage, Property::Map(values));
698 }
699
700 Property::Value::Value(Type type)
701 {
702   switch(type)
703   {
704     case Property::BOOLEAN:
705     {
706       Impl::New(mStorage, false);
707       break;
708     }
709     case Property::FLOAT:
710     {
711       Impl::New(mStorage, 0.f);
712       break;
713     }
714     case Property::INTEGER:
715     {
716       Impl::New(mStorage, 0);
717       break;
718     }
719     case Property::VECTOR2:
720     {
721       Impl::New(mStorage, Vector2::ZERO);
722       break;
723     }
724     case Property::VECTOR3:
725     {
726       Impl::New(mStorage, Vector3::ZERO);
727       break;
728     }
729     case Property::VECTOR4:
730     {
731       Impl::New(mStorage, Vector4::ZERO);
732       break;
733     }
734     case Property::RECTANGLE:
735     {
736       Impl::New(mStorage, Rect<int32_t>());
737       break;
738     }
739     case Property::ROTATION:
740     {
741       Impl::New(mStorage, AngleAxis());
742       break;
743     }
744     case Property::STRING:
745     {
746       Impl::New(mStorage, std::string());
747       break;
748     }
749     case Property::MATRIX:
750     {
751       Impl::New(mStorage, Matrix());
752       break;
753     }
754     case Property::MATRIX3:
755     {
756       Impl::New(mStorage, Matrix3());
757       break;
758     }
759     case Property::ARRAY:
760     {
761       Impl::New(mStorage, Property::Array());
762       break;
763     }
764     case Property::MAP:
765     {
766       Impl::New(mStorage, Property::Map());
767       break;
768     }
769     case Property::EXTENTS:
770     {
771       Impl::New(mStorage, Extents());
772       break;
773     }
774     case Property::NONE:
775     {
776       Impl::New(mStorage);
777       break;
778     }
779   }
780 }
781
782 Property::Value::Value(const Property::Value& value)
783 {
784   Impl::New(mStorage);
785
786   // reuse assignment operator
787   operator=(value);
788 }
789
790 Property::Value::Value(Property::Value&& value) noexcept
791 {
792   // steal the Impl object by doing a copy.
793   std::copy(std::begin(value.mStorage.buffer), std::end(value.mStorage.buffer), std::begin(mStorage.buffer));
794
795   // update the moved from object to NONE state.
796   value.Write().SetType(Property::NONE);
797 }
798
799 Property::Value& Property::Value::operator=(const Property::Value& value)
800 {
801   if(this == &value)
802   {
803     // skip self assignment
804     return *this;
805   }
806
807   // this will call the Impl operator=()
808   Write() = value.Read();
809
810   return *this;
811 }
812
813 Property::Value& Property::Value::operator=(Property::Value&& value) noexcept
814 {
815   if(this != &value)
816   {
817     // delete the existing Impl object
818     Impl::Delete(Write());
819
820     // steal the Impl object by doing a copy.
821     std::copy(std::begin(value.mStorage.buffer), std::end(value.mStorage.buffer), std::begin(mStorage.buffer));
822
823     // update the moved from object to NONE state.
824     value.Write().SetType(Property::NONE);
825   }
826
827   return *this;
828 }
829
830 Property::Value::~Value()
831 {
832   Impl::Delete(Write());
833 }
834
835 Property::Type Property::Value::GetType() const
836 {
837   return Read().GetType();
838 }
839
840 bool Property::Value::Get(bool& booleanValue) const
841 {
842   bool converted = false;
843
844   const auto& obj = Read();
845
846   if(obj.GetType() == BOOLEAN)
847   {
848     booleanValue = obj.GetBool();
849     converted    = true;
850   }
851   else if(obj.GetType() == INTEGER)
852   {
853     booleanValue = obj.GetInt();
854     converted    = true;
855   }
856
857   return converted;
858 }
859
860 bool Property::Value::Get(float& floatValue) const
861 {
862   bool converted = false;
863
864   const auto& obj = Read();
865
866   if(obj.GetType() == FLOAT)
867   {
868     floatValue = obj.GetFloat();
869     converted  = true;
870   }
871   else if(obj.GetType() == BOOLEAN)
872   {
873     floatValue = static_cast<float>(obj.GetBool());
874     converted  = true;
875   }
876   else if(obj.GetType() == INTEGER)
877   {
878     floatValue = static_cast<float>(obj.GetInt());
879     converted  = true;
880   }
881
882   return converted;
883 }
884
885 bool Property::Value::Get(int32_t& integerValue) const
886 {
887   bool converted = false;
888
889   const auto& obj = Read();
890
891   if(obj.GetType() == INTEGER)
892   {
893     integerValue = obj.GetInt();
894     converted    = true;
895   }
896   else if(obj.GetType() == BOOLEAN)
897   {
898     integerValue = obj.GetBool();
899     converted    = true;
900   }
901   else if(obj.GetType() == FLOAT)
902   {
903     integerValue = static_cast<int32_t>(obj.GetFloat());
904     converted    = true;
905   }
906
907   return converted;
908 }
909
910 bool Property::Value::Get(Vector2& vectorValue) const
911 {
912   bool converted = false;
913
914   const auto& obj = Read();
915
916   if(obj.GetType() == VECTOR4)
917   {
918     vectorValue = obj.GetVector4();
919     converted   = true;
920   }
921   else if(obj.GetType() == VECTOR2)
922   {
923     vectorValue = obj.GetVector2();
924     converted   = true;
925   }
926   else if(obj.GetType() == VECTOR3)
927   {
928     vectorValue = obj.GetVector3();
929     converted   = true;
930   }
931
932   return converted;
933 }
934
935 bool Property::Value::Get(Vector3& vectorValue) const
936 {
937   bool converted = false;
938
939   const auto& obj = Read();
940
941   if(obj.GetType() == VECTOR4)
942   {
943     vectorValue = obj.GetVector4();
944     converted   = true;
945   }
946   else if(obj.GetType() == VECTOR2)
947   {
948     vectorValue = obj.GetVector2();
949     converted   = true;
950   }
951   else if(obj.GetType() == VECTOR3)
952   {
953     vectorValue = obj.GetVector3();
954     converted   = true;
955   }
956
957   return converted;
958 }
959
960 bool Property::Value::Get(Vector4& vectorValue) const
961 {
962   bool converted = false;
963
964   const auto& obj = Read();
965
966   if(obj.GetType() == VECTOR4)
967   {
968     vectorValue = obj.GetVector4();
969     converted   = true;
970   }
971   else if(obj.GetType() == VECTOR2)
972   {
973     vectorValue = obj.GetVector2();
974     converted   = true;
975   }
976   else if(obj.GetType() == VECTOR3)
977   {
978     vectorValue = obj.GetVector3();
979     converted   = true;
980   }
981
982   return converted;
983 }
984
985 bool Property::Value::Get(Matrix3& matrixValue) const
986 {
987   bool converted = false;
988
989   const auto& obj = Read();
990
991   if(obj.GetType() == MATRIX3)
992   {
993     matrixValue = obj.GetMatrix3();
994     converted   = true;
995   }
996   return converted;
997 }
998
999 bool Property::Value::Get(Matrix& matrixValue) const
1000 {
1001   bool converted = false;
1002
1003   const auto& obj = Read();
1004
1005   if(obj.GetType() == MATRIX)
1006   {
1007     matrixValue = obj.GetMatrix();
1008     converted   = true;
1009   }
1010   return converted;
1011 }
1012
1013 bool Property::Value::Get(Rect<int32_t>& rectValue) const
1014 {
1015   bool converted = false;
1016
1017   const auto& obj = Read();
1018
1019   if(obj.GetType() == RECTANGLE)
1020   {
1021     rectValue = obj.GetRect();
1022     converted = true;
1023   }
1024   return converted;
1025 }
1026
1027 bool Property::Value::Get(AngleAxis& angleAxisValue) const
1028 {
1029   bool converted = false;
1030
1031   const auto& obj = Read();
1032
1033   if(obj.GetType() == ROTATION)
1034   {
1035     angleAxisValue = obj.GetAngleAxis();
1036     converted      = true;
1037   }
1038   return converted;
1039 }
1040
1041 bool Property::Value::Get(Quaternion& quaternionValue) const
1042 {
1043   bool converted = false;
1044
1045   const auto& obj = Read();
1046
1047   if(obj.GetType() == ROTATION)
1048   {
1049     auto& angleAxis = obj.GetAngleAxis();
1050     quaternionValue = Quaternion(angleAxis.angle, angleAxis.axis);
1051     converted       = true;
1052   }
1053   return converted;
1054 }
1055
1056 bool Property::Value::Get(std::string& stringValue) const
1057 {
1058   bool converted = false;
1059
1060   const auto& obj = Read();
1061
1062   if(obj.GetType() == STRING)
1063   {
1064     stringValue.assign(obj.GetString());
1065     converted = true;
1066   }
1067   return converted;
1068 }
1069
1070 bool Property::Value::Get(Property::Array& arrayValue) const
1071 {
1072   bool converted = false;
1073
1074   const auto& obj = Read();
1075
1076   if(obj.GetType() == ARRAY)
1077   {
1078     arrayValue = obj.GetArray();
1079     converted  = true;
1080   }
1081   return converted;
1082 }
1083
1084 bool Property::Value::Get(Property::Map& mapValue) const
1085 {
1086   bool converted = false;
1087
1088   const auto& obj = Read();
1089
1090   if(obj.GetType() == MAP)
1091   {
1092     mapValue  = obj.GetMap();
1093     converted = true;
1094   }
1095   return converted;
1096 }
1097
1098 Property::Array const* Property::Value::GetArray() const
1099 {
1100   const auto& obj = Read();
1101
1102   if(obj.GetType() == ARRAY)
1103   {
1104     return obj.GetArrayPtr();
1105   }
1106   return nullptr;
1107 }
1108
1109 Property::Array* Property::Value::GetArray()
1110 {
1111   auto& obj = Write();
1112
1113   if(obj.GetType() == ARRAY)
1114   {
1115     return obj.GetArrayPtr();
1116   }
1117   return nullptr;
1118 }
1119
1120 Property::Map const* Property::Value::GetMap() const
1121 {
1122   const auto& obj = Read();
1123
1124   if(obj.GetType() == MAP)
1125   {
1126     return obj.GetMapPtr();
1127   }
1128   return nullptr;
1129 }
1130
1131 Property::Map* Property::Value::GetMap()
1132 {
1133   auto& obj = Write();
1134
1135   if(obj.GetType() == MAP)
1136   {
1137     return obj.GetMapPtr();
1138   }
1139   return nullptr;
1140 }
1141
1142 bool Property::Value::Get(Extents& extentsValue) const
1143 {
1144   bool converted = false;
1145
1146   const auto& obj = Read();
1147
1148   if(obj.GetType() == EXTENTS)
1149   {
1150     extentsValue = obj.GetExtents();
1151     converted    = true;
1152   }
1153   else if(obj.GetType() == VECTOR4)
1154   {
1155     auto& vec4          = obj.GetVector4();
1156     extentsValue.start  = static_cast<uint16_t>(vec4.x);
1157     extentsValue.end    = static_cast<uint16_t>(vec4.y);
1158     extentsValue.top    = static_cast<uint16_t>(vec4.z);
1159     extentsValue.bottom = static_cast<uint16_t>(vec4.w);
1160     converted           = true;
1161   }
1162
1163   return converted;
1164 }
1165
1166 std::ostream& operator<<(std::ostream& stream, const Property::Value& value)
1167 {
1168   const auto& obj = value.Read();
1169
1170   switch(obj.GetType())
1171   {
1172     case Dali::Property::BOOLEAN:
1173     {
1174       stream << obj.GetBool();
1175       break;
1176     }
1177     case Dali::Property::FLOAT:
1178     {
1179       stream << obj.GetFloat();
1180       break;
1181     }
1182     case Dali::Property::INTEGER:
1183     {
1184       stream << obj.GetInt();
1185       break;
1186     }
1187     case Dali::Property::VECTOR2:
1188     {
1189       stream << obj.GetVector2();
1190       break;
1191     }
1192     case Dali::Property::VECTOR3:
1193     {
1194       stream << obj.GetVector3();
1195       break;
1196     }
1197     case Dali::Property::VECTOR4:
1198     {
1199       stream << obj.GetVector4();
1200       break;
1201     }
1202     case Dali::Property::MATRIX3:
1203     {
1204       stream << obj.GetMatrix3();
1205       break;
1206     }
1207     case Dali::Property::MATRIX:
1208     {
1209       stream << obj.GetMatrix();
1210       break;
1211     }
1212     case Dali::Property::RECTANGLE:
1213     {
1214       stream << obj.GetRect();
1215       break;
1216     }
1217     case Dali::Property::ROTATION:
1218     {
1219       stream << obj.GetAngleAxis();
1220       break;
1221     }
1222     case Dali::Property::STRING:
1223     {
1224       stream << obj.GetString();
1225       break;
1226     }
1227     case Dali::Property::ARRAY:
1228     {
1229       stream << obj.GetArray();
1230       break;
1231     }
1232     case Dali::Property::MAP:
1233     {
1234       stream << obj.GetMap();
1235       break;
1236     }
1237     case Dali::Property::EXTENTS:
1238     {
1239       stream << obj.GetExtents();
1240       break;
1241     }
1242     case Dali::Property::NONE:
1243     {
1244       stream << "undefined type";
1245     }
1246   }
1247   return stream;
1248 }
1249
1250 } // namespace Dali