2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/public-api/object/property-value.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/common/extents.h>
27 #include <dali/public-api/math/angle-axis.h>
28 #include <dali/public-api/math/matrix.h>
29 #include <dali/public-api/math/matrix3.h>
30 #include <dali/public-api/math/quaternion.h>
31 #include <dali/public-api/math/radian.h>
32 #include <dali/public-api/math/rect.h>
33 #include <dali/public-api/math/vector2.h>
34 #include <dali/public-api/math/vector3.h>
35 #include <dali/public-api/math/vector4.h>
36 #include <dali/public-api/object/property-array.h>
37 #include <dali/public-api/object/property-map.h>
38 #include <dali/public-api/object/property-types.h>
43 struct Property::Value::Impl
47 // Destroy the current object stored in Data union memory.
51 Impl(const Impl&) = delete;
53 Impl(Impl&&) = delete;
55 Impl& operator=(Impl&&) = delete;
59 static_assert(sizeof(Impl) == 16);
60 static_assert(alignof(Impl) == alignof(Impl*));
62 SetType(Property::NONE);
65 Impl(bool booleanValue)
67 SetType(Property::BOOLEAN);
68 mData.mBool.member = booleanValue;
71 Impl(float floatValue)
73 SetType(Property::FLOAT);
74 mData.mFloat.member = floatValue;
77 Impl(int32_t integerValue)
79 SetType(Property::INTEGER);
80 mData.mInt.member = integerValue;
83 Impl(Vector2 vectorValue)
85 SetType(Property::VECTOR2);
86 ConstructInplace(mData.mVector2.member, std::move(vectorValue));
89 Impl(Vector3 vectorValue)
91 SetType(Property::VECTOR3);
92 ConstructInplace(mData.mVector3.member, std::move(vectorValue));
95 Impl(Extents extentsValue)
97 SetType(Property::EXTENTS);
98 ConstructInplace(mData.mExtents.member, std::move(extentsValue));
101 Impl(Property::Map mapValue)
103 SetType(Property::MAP);
104 ConstructInplace(mData.mMap.member, std::move(mapValue));
107 Impl(Property::Array arrayValue)
109 SetType(Property::ARRAY);
110 ConstructInplace(mData.mArray.member, std::move(arrayValue));
113 Impl(std::string stringValue)
115 SetType(Property::STRING);
116 mData.mString.member = new std::string(std::move(stringValue));
119 Impl(Rect<int32_t> rectValue)
121 SetType(Property::RECTANGLE);
122 mData.mRect.member = new Rect<int32_t>(std::move(rectValue));
125 Impl(Vector4 vectorValue)
127 SetType(Property::VECTOR4);
128 mData.mVector4.member = new Vector4(std::move(vectorValue));
131 Impl(Matrix3 matrixValue)
133 SetType(Property::MATRIX3);
134 mData.mMatrix3.member = new Matrix3(std::move(matrixValue));
137 Impl(Matrix matrixValue)
139 SetType(Property::MATRIX);
140 mData.mMatrix.member = new Matrix(std::move(matrixValue));
143 Impl(AngleAxis angleAxisValue)
145 SetType(Property::ROTATION);
146 mData.mAngleAxis.member = new AngleAxis(std::move(angleAxisValue));
151 return mData.mType.type;
156 return mData.mBool.member;
159 int32_t GetInt() const
161 return mData.mInt.member;
164 float GetFloat() const
166 return mData.mFloat.member;
169 const Extents& GetExtents() const
171 return mData.mExtents.member;
174 const Vector2& GetVector2() const
176 return mData.mVector2.member;
179 const Vector3& GetVector3() const
181 return mData.mVector3.member;
184 const Property::Map& GetMap() const
186 return mData.mMap.member;
189 const Property::Array& GetArray() const
191 return mData.mArray.member;
194 const Vector4& GetVector4() const
196 return *(mData.mVector4.member);
199 const Matrix3& GetMatrix3() const
201 return *(mData.mMatrix3.member);
204 const Matrix& GetMatrix() const
206 return *(mData.mMatrix.member);
209 const AngleAxis& GetAngleAxis() const
211 return *(mData.mAngleAxis.member);
214 const std::string& GetString() const
216 return *(mData.mString.member);
219 const Rect<int32_t>& GetRect() const
221 return *(mData.mRect.member);
224 Property::Map* GetMapPtr()
226 return &(mData.mMap.member);
229 Property::Array* GetArrayPtr()
231 return &(mData.mArray.member);
234 Impl& operator=(const Impl& other)
236 const bool isSameType = GetType() == other.GetType();
241 SetType(other.GetType());
250 case Property::BOOLEAN:
252 mData.mBool.member = other.GetBool();
255 case Property::FLOAT:
257 mData.mFloat.member = other.GetFloat();
260 case Property::INTEGER:
262 mData.mInt.member = other.GetInt();
265 case Property::EXTENTS:
267 auto obj = other.GetExtents();
268 ConstructInplace(mData.mExtents.member, std::move(obj));
271 case Property::VECTOR2:
273 auto obj = other.GetVector2();
274 ConstructInplace(mData.mVector2.member, std::move(obj));
277 case Property::VECTOR3:
279 auto obj = other.GetVector3();
280 ConstructInplace(mData.mVector3.member, std::move(obj));
283 case Property::ARRAY:
285 auto obj = other.GetArray();
286 ConstructInplace(mData.mArray.member, std::move(obj));
291 auto obj = other.GetMap();
292 ConstructInplace(mData.mMap.member, std::move(obj));
295 case Property::VECTOR4:
299 *mData.mVector4.member = other.GetVector4();
303 mData.mVector4.member = new Vector4(other.GetVector4());
307 case Property::MATRIX3:
311 *mData.mMatrix3.member = other.GetMatrix3();
315 mData.mMatrix3.member = new Matrix3(other.GetMatrix3());
319 case Property::MATRIX:
323 *mData.mMatrix.member = other.GetMatrix();
327 mData.mMatrix.member = new Matrix(other.GetMatrix());
331 case Property::RECTANGLE:
335 *mData.mRect.member = other.GetRect();
339 mData.mRect.member = new Rect<int32_t>(other.GetRect());
343 case Property::ROTATION:
347 *mData.mAngleAxis.member = other.GetAngleAxis();
351 mData.mAngleAxis.member = new AngleAxis(other.GetAngleAxis());
355 case Property::STRING:
359 *mData.mString.member = other.GetString();
363 mData.mString.member = new std::string(other.GetString());
372 void SetType(Type typeValue)
374 mData.mType.type = typeValue;
378 * This helper function takes a typed(Tp) memory location( member)
379 * and a object of same type( val ) and move constructs a new object of
380 * same type(Tp) in the memory location( member) using placement new.
381 * after this function call member location will have a object of type Tp.
383 template<typename Tp>
384 void ConstructInplace(Tp& member, Tp&& val)
386 new(&member) Tp(std::forward<Tp>(val));
390 * Destroy the object created in the Data union memory by probing the
391 * type and calling the appropriate destructor.
392 * and also reset the type and memory location to reflect that .
399 case Property::BOOLEAN:
400 case Property::FLOAT:
401 case Property::INTEGER:
403 break; // nothing to do
405 case Property::EXTENTS:
407 mData.mExtents.member.~Extents();
410 case Property::VECTOR2:
412 mData.mVector2.member.~Vector2();
415 case Property::VECTOR3:
417 mData.mVector3.member.~Vector3();
420 case Property::ARRAY:
422 using array = Property::Array;
423 mData.mArray.member.~array();
428 using map = Property::Map;
429 mData.mMap.member.~map();
432 case Property::VECTOR4:
434 delete mData.mVector4.member;
437 case Property::MATRIX3:
439 delete mData.mMatrix3.member;
442 case Property::MATRIX:
444 delete mData.mMatrix.member;
447 case Property::RECTANGLE:
449 delete mData.mRect.member;
452 case Property::ROTATION:
454 delete mData.mAngleAxis.member;
457 case Property::STRING:
459 delete mData.mString.member;
466 * This wrapper struct is used for
467 * storing Type in every union member
468 * and can acess it from non active member
469 * of the uninon without invoking UB. this is
470 * possible because of CIS(common initial sequence)
471 * http://eel.is/c++draft/class.mem#general-25
481 * Tagged union implementation.
483 * This Data union contains non trivial data
484 * types Map and Array, the default constructor
485 * and destructors are deleted by the compiler
486 * so we provided empty constructor and destructor
487 * just to pacify the compiler.
488 * The only job of this union to give a typed memory buffer to the
489 * Impl class which can construct the appropriate object
490 * using placement new.
491 * As Impl class explicitly construct the object and keeps track of the
492 * object it creates and then destroys them in the ~Impl() this will not leak
504 UnionMember<bool> mBool;
505 UnionMember<int32_t> mInt;
506 UnionMember<float> mFloat;
507 UnionMember<Extents> mExtents;
508 UnionMember<Vector2> mVector2;
509 UnionMember<Vector3> mVector3;
510 UnionMember<Property::Map> mMap;
511 UnionMember<Property::Array> mArray;
512 UnionMember<Vector4*> mVector4;
513 UnionMember<Matrix3*> mMatrix3;
514 UnionMember<Matrix*> mMatrix;
515 UnionMember<AngleAxis*> mAngleAxis;
516 UnionMember<std::string*> mString;
517 UnionMember<Rect<int32_t>*> mRect;
527 Property::Value::Value()
532 Property::Value::Value(bool booleanValue)
533 : mImpl(new Impl(booleanValue))
537 Property::Value::Value(float floatValue)
538 : mImpl(new Impl(floatValue))
542 Property::Value::Value(int32_t integerValue)
543 : mImpl(new Impl(integerValue))
547 Property::Value::Value(const Vector2& vectorValue)
548 : mImpl(new Impl(vectorValue))
552 Property::Value::Value(const Vector3& vectorValue)
553 : mImpl(new Impl(vectorValue))
557 Property::Value::Value(const Vector4& vectorValue)
558 : mImpl(new Impl(vectorValue))
562 Property::Value::Value(const Matrix3& matrixValue)
563 : mImpl(new Impl(matrixValue))
567 Property::Value::Value(const Matrix& matrixValue)
568 : mImpl(new Impl(matrixValue))
572 Property::Value::Value(const Rect<int32_t>& rectValue)
573 : mImpl(new Impl(rectValue))
577 Property::Value::Value(const Rect<float>& rectValue)
578 : mImpl(new Impl(Vector4(rectValue.x, rectValue.y, rectValue.width, rectValue.height)))
582 Property::Value::Value(const AngleAxis& angleAxisValue)
583 : mImpl(new Impl(angleAxisValue))
587 Property::Value::Value(const Quaternion& quaternionValue)
589 AngleAxis angleAxisValue;
590 quaternionValue.ToAxisAngle(angleAxisValue.axis, angleAxisValue.angle);
591 mImpl = new Impl(std::move(angleAxisValue));
594 Property::Value::Value(std::string stringValue)
595 : mImpl(new Impl(std::move(stringValue)))
599 Property::Value::Value(const char* stringValue)
602 if(stringValue) // string constructor is undefined with nullptr
604 mImpl = new Impl(std::string(stringValue));
608 mImpl = new Impl(std::string());
612 Property::Value::Value(Property::Array arrayValue)
613 : mImpl(new Impl(std::move(arrayValue)))
617 Property::Value::Value(Property::Map mapValue)
618 : mImpl(new Impl(std::move(mapValue)))
622 Property::Value::Value(const Extents& extentsValue)
623 : mImpl(new Impl(extentsValue))
627 Property::Value::Value(const std::initializer_list<KeyValuePair>& values)
628 : mImpl(new Impl(Property::Map(values)))
632 Property::Value::Value(Type type)
637 case Property::BOOLEAN:
639 mImpl = new Impl(false);
642 case Property::FLOAT:
644 mImpl = new Impl(0.f);
647 case Property::INTEGER:
652 case Property::VECTOR2:
654 mImpl = new Impl(Vector2::ZERO);
657 case Property::VECTOR3:
659 mImpl = new Impl(Vector3::ZERO);
662 case Property::VECTOR4:
664 mImpl = new Impl(Vector4::ZERO);
667 case Property::RECTANGLE:
669 mImpl = new Impl(Rect<int32_t>());
672 case Property::ROTATION:
674 mImpl = new Impl(AngleAxis());
677 case Property::STRING:
679 mImpl = new Impl(std::string());
682 case Property::MATRIX:
684 mImpl = new Impl(Matrix());
687 case Property::MATRIX3:
689 mImpl = new Impl(Matrix3());
692 case Property::ARRAY:
694 mImpl = new Impl(Property::Array());
699 mImpl = new Impl(Property::Map());
702 case Property::EXTENTS:
704 mImpl = new Impl(Extents());
709 // No need to create an Impl
715 Property::Value::Value(const Property::Value& value)
718 // reuse assignment operator
722 Property::Value::Value(Property::Value&& value) noexcept
725 value.mImpl = nullptr;
728 Property::Value& Property::Value::operator=(const Property::Value& value)
732 // skip self assignment
743 *mImpl = *(value.mImpl);
754 Property::Value& Property::Value::operator=(Property::Value&& value) noexcept
760 value.mImpl = nullptr;
766 Property::Value::~Value()
771 Property::Type Property::Value::GetType() const
773 return mImpl ? mImpl->GetType() : Property::NONE;
776 bool Property::Value::Get(bool& booleanValue) const
778 bool converted = false;
781 if(mImpl->GetType() == BOOLEAN)
783 booleanValue = mImpl->GetBool();
786 else if(mImpl->GetType() == INTEGER)
788 booleanValue = mImpl->GetInt();
795 bool Property::Value::Get(float& floatValue) const
797 bool converted = false;
800 if(mImpl->GetType() == FLOAT)
802 floatValue = mImpl->GetFloat();
805 else if(mImpl->GetType() == BOOLEAN)
807 floatValue = static_cast<float>(mImpl->GetBool());
810 else if(mImpl->GetType() == INTEGER)
812 floatValue = static_cast<float>(mImpl->GetInt());
819 bool Property::Value::Get(int32_t& integerValue) const
821 bool converted = false;
824 if(mImpl->GetType() == INTEGER)
826 integerValue = mImpl->GetInt();
829 else if(mImpl->GetType() == BOOLEAN)
831 integerValue = mImpl->GetBool();
834 else if(mImpl->GetType() == FLOAT)
836 integerValue = static_cast<int32_t>(mImpl->GetFloat());
843 bool Property::Value::Get(Vector2& vectorValue) const
845 bool converted = false;
848 if(mImpl->GetType() == VECTOR4)
850 vectorValue = mImpl->GetVector4();
853 else if(mImpl->GetType() == VECTOR2)
855 vectorValue = mImpl->GetVector2();
858 else if(mImpl->GetType() == VECTOR3)
860 vectorValue = mImpl->GetVector3();
867 bool Property::Value::Get(Vector3& vectorValue) const
869 bool converted = false;
872 if(mImpl->GetType() == VECTOR4)
874 vectorValue = mImpl->GetVector4();
877 else if(mImpl->GetType() == VECTOR2)
879 vectorValue = mImpl->GetVector2();
882 else if(mImpl->GetType() == VECTOR3)
884 vectorValue = mImpl->GetVector3();
891 bool Property::Value::Get(Vector4& vectorValue) const
893 bool converted = false;
896 if(mImpl->GetType() == VECTOR4)
898 vectorValue = mImpl->GetVector4();
901 else if(mImpl->GetType() == VECTOR2)
903 vectorValue = mImpl->GetVector2();
906 else if(mImpl->GetType() == VECTOR3)
908 vectorValue = mImpl->GetVector3();
915 bool Property::Value::Get(Matrix3& matrixValue) const
917 bool converted = false;
918 if(mImpl && (mImpl->GetType() == MATRIX3))
920 matrixValue = mImpl->GetMatrix3();
926 bool Property::Value::Get(Matrix& matrixValue) const
928 bool converted = false;
929 if(mImpl && (mImpl->GetType() == MATRIX))
931 matrixValue = mImpl->GetMatrix();
937 bool Property::Value::Get(Rect<int32_t>& rectValue) const
939 bool converted = false;
940 if(mImpl && (mImpl->GetType() == RECTANGLE))
942 rectValue = mImpl->GetRect();
948 bool Property::Value::Get(AngleAxis& angleAxisValue) const
950 bool converted = false;
951 if(mImpl && (mImpl->GetType() == ROTATION))
953 angleAxisValue = mImpl->GetAngleAxis();
959 bool Property::Value::Get(Quaternion& quaternionValue) const
961 bool converted = false;
962 if(mImpl && (mImpl->GetType() == ROTATION))
964 auto& obj = mImpl->GetAngleAxis();
965 quaternionValue = Quaternion(obj.angle, obj.axis);
971 bool Property::Value::Get(std::string& stringValue) const
973 bool converted = false;
974 if(mImpl && (mImpl->GetType() == STRING))
976 stringValue.assign(mImpl->GetString());
982 bool Property::Value::Get(Property::Array& arrayValue) const
984 bool converted = false;
985 if(mImpl && (mImpl->GetType() == ARRAY))
987 arrayValue = mImpl->GetArray();
993 bool Property::Value::Get(Property::Map& mapValue) const
995 bool converted = false;
996 if(mImpl && (mImpl->GetType() == MAP))
998 mapValue = mImpl->GetMap();
1004 Property::Array const* Property::Value::GetArray() const
1006 if(mImpl && (mImpl->GetType() == ARRAY))
1008 return mImpl->GetArrayPtr();
1013 Property::Array* Property::Value::GetArray()
1015 Property::Array* array = nullptr;
1016 if(mImpl && (mImpl->GetType() == ARRAY)) // type cannot change in mImpl so array is allocated
1018 array = mImpl->GetArrayPtr();
1023 Property::Map const* Property::Value::GetMap() const
1025 Property::Map* map = nullptr;
1026 if(mImpl && (mImpl->GetType() == MAP)) // type cannot change in mImpl so map is allocated
1028 map = mImpl->GetMapPtr();
1033 Property::Map* Property::Value::GetMap()
1035 if(mImpl && (mImpl->GetType() == MAP))
1037 return mImpl->GetMapPtr();
1042 bool Property::Value::Get(Extents& extentsValue) const
1044 bool converted = false;
1047 if(mImpl->GetType() == EXTENTS)
1049 extentsValue = mImpl->GetExtents();
1052 else if(mImpl->GetType() == VECTOR4)
1054 auto& obj = mImpl->GetVector4();
1055 extentsValue.start = static_cast<uint16_t>(obj.x);
1056 extentsValue.end = static_cast<uint16_t>(obj.y);
1057 extentsValue.top = static_cast<uint16_t>(obj.z);
1058 extentsValue.bottom = static_cast<uint16_t>(obj.w);
1065 std::ostream& operator<<(std::ostream& stream, const Property::Value& value)
1069 auto obj = value.mImpl;
1071 switch(obj->GetType())
1073 case Dali::Property::BOOLEAN:
1075 stream << obj->GetBool();
1078 case Dali::Property::FLOAT:
1080 stream << obj->GetFloat();
1083 case Dali::Property::INTEGER:
1085 stream << obj->GetInt();
1088 case Dali::Property::VECTOR2:
1090 stream << obj->GetVector2();
1093 case Dali::Property::VECTOR3:
1095 stream << obj->GetVector3();
1098 case Dali::Property::VECTOR4:
1100 stream << obj->GetVector4();
1103 case Dali::Property::MATRIX3:
1105 stream << obj->GetMatrix3();
1108 case Dali::Property::MATRIX:
1110 stream << obj->GetMatrix();
1113 case Dali::Property::RECTANGLE:
1115 stream << obj->GetRect();
1118 case Dali::Property::ROTATION:
1120 stream << obj->GetAngleAxis();
1123 case Dali::Property::STRING:
1125 stream << obj->GetString();
1128 case Dali::Property::ARRAY:
1130 stream << obj->GetArray();
1133 case Dali::Property::MAP:
1135 stream << obj->GetMap();
1138 case Dali::Property::EXTENTS:
1140 stream << obj->GetExtents();
1143 case Dali::Property::NONE:
1144 { // mImpl will be a nullptr, there's no way to get to this case
1150 stream << "undefined type";