2 * Copyright (c) 2022 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>
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>
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.
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) ).
61 struct Property::Value::Impl
63 template<typename... Args>
64 static Impl* New(Property::Value::Storage& buffer, Args... args)
66 return new(&buffer) Impl(std::forward<Args>(args)...);
69 static void Delete(Property::Value::Impl& impl)
76 // Destroy the current object stored in Data union memory.
80 Impl(const Impl&) = delete;
82 Impl(Impl&&) = delete;
84 Impl& operator=(Impl&&) = delete;
88 static_assert(sizeof(Impl) == 16);
89 static_assert(alignof(Impl) == alignof(Impl*));
91 SetType(Property::NONE);
94 Impl(bool booleanValue)
96 SetType(Property::BOOLEAN);
97 mData.mBool.member = booleanValue;
100 Impl(float floatValue)
102 SetType(Property::FLOAT);
103 mData.mFloat.member = floatValue;
106 Impl(int32_t integerValue)
108 SetType(Property::INTEGER);
109 mData.mInt.member = integerValue;
112 Impl(Vector2 vectorValue)
114 SetType(Property::VECTOR2);
115 ConstructInplace(mData.mVector2.member, std::move(vectorValue));
118 Impl(Vector3 vectorValue)
120 SetType(Property::VECTOR3);
121 ConstructInplace(mData.mVector3.member, std::move(vectorValue));
124 Impl(Extents extentsValue)
126 SetType(Property::EXTENTS);
127 ConstructInplace(mData.mExtents.member, std::move(extentsValue));
130 Impl(Property::Map mapValue)
132 SetType(Property::MAP);
133 ConstructInplace(mData.mMap.member, std::move(mapValue));
136 Impl(Property::Array arrayValue)
138 SetType(Property::ARRAY);
139 ConstructInplace(mData.mArray.member, std::move(arrayValue));
142 Impl(std::string stringValue)
144 SetType(Property::STRING);
145 mData.mString.member = new std::string(std::move(stringValue));
148 Impl(Rect<int32_t> rectValue)
150 SetType(Property::RECTANGLE);
151 mData.mRect.member = new Rect<int32_t>(std::move(rectValue));
154 Impl(Vector4 vectorValue)
156 SetType(Property::VECTOR4);
157 mData.mVector4.member = new Vector4(std::move(vectorValue));
160 Impl(Matrix3 matrixValue)
162 SetType(Property::MATRIX3);
163 mData.mMatrix3.member = new Matrix3(std::move(matrixValue));
166 Impl(Matrix matrixValue)
168 SetType(Property::MATRIX);
169 mData.mMatrix.member = new Matrix(std::move(matrixValue));
172 Impl(AngleAxis angleAxisValue)
174 SetType(Property::ROTATION);
175 mData.mAngleAxis.member = new AngleAxis(std::move(angleAxisValue));
180 return mData.mType.type;
185 return mData.mBool.member;
188 int32_t GetInt() const
190 return mData.mInt.member;
193 float GetFloat() const
195 return mData.mFloat.member;
198 const Extents& GetExtents() const
200 return mData.mExtents.member;
203 const Vector2& GetVector2() const
205 return mData.mVector2.member;
208 const Vector3& GetVector3() const
210 return mData.mVector3.member;
213 const Property::Map& GetMap() const
215 return mData.mMap.member;
218 const Property::Array& GetArray() const
220 return mData.mArray.member;
223 const Vector4& GetVector4() const
225 return *(mData.mVector4.member);
228 const Matrix3& GetMatrix3() const
230 return *(mData.mMatrix3.member);
233 const Matrix& GetMatrix() const
235 return *(mData.mMatrix.member);
238 const AngleAxis& GetAngleAxis() const
240 return *(mData.mAngleAxis.member);
243 const std::string& GetString() const
245 return *(mData.mString.member);
248 const Rect<int32_t>& GetRect() const
250 return *(mData.mRect.member);
253 Property::Map* GetMapPtr()
255 return &(mData.mMap.member);
258 const Property::Map* GetMapPtr() const
260 return &(mData.mMap.member);
263 Property::Array* GetArrayPtr()
265 return &(mData.mArray.member);
268 const Property::Array* GetArrayPtr() const
270 return &(mData.mArray.member);
273 Impl& operator=(const Impl& other)
275 const bool isSameType = GetType() == other.GetType();
280 SetType(other.GetType());
289 case Property::BOOLEAN:
291 mData.mBool.member = other.GetBool();
294 case Property::FLOAT:
296 mData.mFloat.member = other.GetFloat();
299 case Property::INTEGER:
301 mData.mInt.member = other.GetInt();
304 case Property::EXTENTS:
306 auto obj = other.GetExtents();
307 ConstructInplace(mData.mExtents.member, std::move(obj));
310 case Property::VECTOR2:
312 auto obj = other.GetVector2();
313 ConstructInplace(mData.mVector2.member, std::move(obj));
316 case Property::VECTOR3:
318 auto obj = other.GetVector3();
319 ConstructInplace(mData.mVector3.member, std::move(obj));
322 case Property::ARRAY:
326 mData.mArray.member = other.GetArray();
330 auto obj = other.GetArray();
331 ConstructInplace(mData.mArray.member, std::move(obj));
339 mData.mMap.member = other.GetMap();
343 auto obj = other.GetMap();
344 ConstructInplace(mData.mMap.member, std::move(obj));
348 case Property::VECTOR4:
352 *mData.mVector4.member = other.GetVector4();
356 mData.mVector4.member = new Vector4(other.GetVector4());
360 case Property::MATRIX3:
364 *mData.mMatrix3.member = other.GetMatrix3();
368 mData.mMatrix3.member = new Matrix3(other.GetMatrix3());
372 case Property::MATRIX:
376 *mData.mMatrix.member = other.GetMatrix();
380 mData.mMatrix.member = new Matrix(other.GetMatrix());
384 case Property::RECTANGLE:
388 *mData.mRect.member = other.GetRect();
392 mData.mRect.member = new Rect<int32_t>(other.GetRect());
396 case Property::ROTATION:
400 *mData.mAngleAxis.member = other.GetAngleAxis();
404 mData.mAngleAxis.member = new AngleAxis(other.GetAngleAxis());
408 case Property::STRING:
412 *mData.mString.member = other.GetString();
416 mData.mString.member = new std::string(other.GetString());
424 bool operator==(const Impl& other) const
426 const bool isSameType = GetType() == other.GetType();
430 // We don't support to compare with different type.
440 case Property::BOOLEAN:
442 return mData.mBool.member == other.mData.mBool.member;
444 case Property::FLOAT:
446 return Equals(mData.mFloat.member, other.mData.mFloat.member);
448 case Property::INTEGER:
450 return mData.mInt.member == other.mData.mInt.member;
452 case Property::VECTOR2:
454 return mData.mVector2.member == other.mData.mVector2.member;
456 case Property::VECTOR3:
458 return mData.mVector3.member == other.mData.mVector3.member;
460 case Property::VECTOR4:
462 return *mData.mVector4.member == *other.mData.mVector4.member;
464 case Property::MATRIX3:
466 return *mData.mMatrix3.member == *other.mData.mMatrix3.member;
468 case Property::MATRIX:
470 return *mData.mMatrix.member == *other.mData.mMatrix.member;
472 case Property::RECTANGLE:
474 return *mData.mRect.member == *other.mData.mRect.member;
476 case Property::ROTATION:
478 return *mData.mAngleAxis.member == *other.mData.mAngleAxis.member;
480 case Property::STRING:
482 return *mData.mString.member == *other.mData.mString.member;
484 case Property::EXTENTS:
486 return mData.mExtents.member == other.mData.mExtents.member;
488 case Property::ARRAY:
491 // TODO : Need to support this case
498 void SetType(Type typeValue)
500 mData.mType.type = typeValue;
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.
510 template<typename Tp>
511 void ConstructInplace(Tp& member, Tp&& val)
513 new(&member) Tp(std::forward<Tp>(val));
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 .
526 case Property::BOOLEAN:
527 case Property::FLOAT:
528 case Property::INTEGER:
530 break; // nothing to do
532 case Property::EXTENTS:
534 mData.mExtents.member.~Extents();
537 case Property::VECTOR2:
539 mData.mVector2.member.~Vector2();
542 case Property::VECTOR3:
544 mData.mVector3.member.~Vector3();
547 case Property::ARRAY:
549 using array = Property::Array;
550 mData.mArray.member.~array();
555 using map = Property::Map;
556 mData.mMap.member.~map();
559 case Property::VECTOR4:
561 delete mData.mVector4.member;
564 case Property::MATRIX3:
566 delete mData.mMatrix3.member;
569 case Property::MATRIX:
571 delete mData.mMatrix.member;
574 case Property::RECTANGLE:
576 delete mData.mRect.member;
579 case Property::ROTATION:
581 delete mData.mAngleAxis.member;
584 case Property::STRING:
586 delete mData.mString.member;
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
608 * Tagged union implementation.
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
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;
655 * Safe way to read an already constructed Object from a buffer.
657 const Property::Value::Impl& Property::Value::Read() const
659 return *(std::launder(reinterpret_cast<const Property::Value::Impl*>(mStorage.buffer)));
662 Property::Value::Impl& Property::Value::Write()
664 return *(std::launder(reinterpret_cast<Property::Value::Impl*>(mStorage.buffer)));
667 Property::Value::Value()
671 static_assert(sizeof(Value) == 16);
672 static_assert(alignof(Value) == alignof(Value*));
675 Property::Value::Value(bool booleanValue)
677 Impl::New(mStorage, booleanValue);
680 Property::Value::Value(float floatValue)
682 Impl::New(mStorage, floatValue);
685 Property::Value::Value(int32_t integerValue)
687 Impl::New(mStorage, integerValue);
690 Property::Value::Value(const Vector2& vectorValue)
692 Impl::New(mStorage, vectorValue);
695 Property::Value::Value(const Vector3& vectorValue)
697 Impl::New(mStorage, vectorValue);
700 Property::Value::Value(const Vector4& vectorValue)
702 Impl::New(mStorage, vectorValue);
705 Property::Value::Value(const Matrix3& matrixValue)
707 Impl::New(mStorage, matrixValue);
710 Property::Value::Value(const Matrix& matrixValue)
712 Impl::New(mStorage, matrixValue);
715 Property::Value::Value(const Rect<int32_t>& rectValue)
717 Impl::New(mStorage, rectValue);
720 Property::Value::Value(const Rect<float>& rectValue)
722 Impl::New(mStorage, Vector4(rectValue.x, rectValue.y, rectValue.width, rectValue.height));
725 Property::Value::Value(const AngleAxis& angleAxisValue)
727 Impl::New(mStorage, angleAxisValue);
730 Property::Value::Value(const Quaternion& quaternionValue)
732 AngleAxis angleAxisValue;
733 quaternionValue.ToAxisAngle(angleAxisValue.axis, angleAxisValue.angle);
734 Impl::New(mStorage, std::move(angleAxisValue));
737 Property::Value::Value(std::string stringValue)
739 Impl::New(mStorage, std::move(stringValue));
742 Property::Value::Value(const char* stringValue)
744 if(stringValue) // string constructor is undefined with nullptr
746 Impl::New(mStorage, std::string(stringValue));
750 Impl::New(mStorage, std::string());
754 Property::Value::Value(Property::Array arrayValue)
756 Impl::New(mStorage, std::move(arrayValue));
759 Property::Value::Value(Property::Map mapValue)
761 Impl::New(mStorage, std::move(mapValue));
764 Property::Value::Value(const Extents& extentsValue)
766 Impl::New(mStorage, extentsValue);
769 Property::Value::Value(const std::initializer_list<KeyValuePair>& values)
771 Impl::New(mStorage, Property::Map(values));
774 Property::Value::Value(Type type)
778 case Property::BOOLEAN:
780 Impl::New(mStorage, false);
783 case Property::FLOAT:
785 Impl::New(mStorage, 0.f);
788 case Property::INTEGER:
790 Impl::New(mStorage, 0);
793 case Property::VECTOR2:
795 Impl::New(mStorage, Vector2::ZERO);
798 case Property::VECTOR3:
800 Impl::New(mStorage, Vector3::ZERO);
803 case Property::VECTOR4:
805 Impl::New(mStorage, Vector4::ZERO);
808 case Property::RECTANGLE:
810 Impl::New(mStorage, Rect<int32_t>());
813 case Property::ROTATION:
815 Impl::New(mStorage, AngleAxis());
818 case Property::STRING:
820 Impl::New(mStorage, std::string());
823 case Property::MATRIX:
825 Impl::New(mStorage, Matrix());
828 case Property::MATRIX3:
830 Impl::New(mStorage, Matrix3());
833 case Property::ARRAY:
835 Impl::New(mStorage, Property::Array());
840 Impl::New(mStorage, Property::Map());
843 case Property::EXTENTS:
845 Impl::New(mStorage, Extents());
856 Property::Value::Value(const Property::Value& value)
860 // reuse assignment operator
864 Property::Value::Value(Property::Value&& value) noexcept
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));
869 // update the moved from object to NONE state.
870 value.Write().SetType(Property::NONE);
873 Property::Value& Property::Value::operator=(const Property::Value& value)
877 // skip self assignment
881 // this will call the Impl operator=()
882 Write() = value.Read();
887 Property::Value& Property::Value::operator=(Property::Value&& value) noexcept
891 // delete the existing Impl object
892 Impl::Delete(Write());
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));
897 // update the moved from object to NONE state.
898 value.Write().SetType(Property::NONE);
904 bool Property::Value::operator==(const Property::Value& rhs) const
906 // this will call the Impl operator==()
907 return Read() == rhs.Read();
910 Property::Value::~Value()
912 Impl::Delete(Write());
915 Property::Type Property::Value::GetType() const
917 return Read().GetType();
920 bool Property::Value::Get(bool& booleanValue) const
922 bool converted = false;
924 const auto& obj = Read();
926 if(obj.GetType() == BOOLEAN)
928 booleanValue = obj.GetBool();
931 else if(obj.GetType() == INTEGER)
933 booleanValue = obj.GetInt();
940 bool Property::Value::Get(float& floatValue) const
942 bool converted = false;
944 const auto& obj = Read();
946 if(obj.GetType() == FLOAT)
948 floatValue = obj.GetFloat();
951 else if(obj.GetType() == BOOLEAN)
953 floatValue = static_cast<float>(obj.GetBool());
956 else if(obj.GetType() == INTEGER)
958 floatValue = static_cast<float>(obj.GetInt());
965 bool Property::Value::Get(int32_t& integerValue) const
967 bool converted = false;
969 const auto& obj = Read();
971 if(obj.GetType() == INTEGER)
973 integerValue = obj.GetInt();
976 else if(obj.GetType() == BOOLEAN)
978 integerValue = obj.GetBool();
981 else if(obj.GetType() == FLOAT)
983 integerValue = static_cast<int32_t>(obj.GetFloat());
990 bool Property::Value::Get(Vector2& vectorValue) const
992 bool converted = false;
994 const auto& obj = Read();
996 if(obj.GetType() == VECTOR4)
998 vectorValue = obj.GetVector4();
1001 else if(obj.GetType() == VECTOR2)
1003 vectorValue = obj.GetVector2();
1006 else if(obj.GetType() == VECTOR3)
1008 vectorValue = obj.GetVector3();
1015 bool Property::Value::Get(Vector3& vectorValue) const
1017 bool converted = false;
1019 const auto& obj = Read();
1021 if(obj.GetType() == VECTOR4)
1023 vectorValue = obj.GetVector4();
1026 else if(obj.GetType() == VECTOR2)
1028 vectorValue = obj.GetVector2();
1031 else if(obj.GetType() == VECTOR3)
1033 vectorValue = obj.GetVector3();
1040 bool Property::Value::Get(Vector4& vectorValue) const
1042 bool converted = false;
1044 const auto& obj = Read();
1046 if(obj.GetType() == VECTOR4)
1048 vectorValue = obj.GetVector4();
1051 else if(obj.GetType() == VECTOR2)
1053 vectorValue = obj.GetVector2();
1056 else if(obj.GetType() == VECTOR3)
1058 vectorValue = obj.GetVector3();
1065 bool Property::Value::Get(Matrix3& matrixValue) const
1067 bool converted = false;
1069 const auto& obj = Read();
1071 if(obj.GetType() == MATRIX3)
1073 matrixValue = obj.GetMatrix3();
1079 bool Property::Value::Get(Matrix& matrixValue) const
1081 bool converted = false;
1083 const auto& obj = Read();
1085 if(obj.GetType() == MATRIX)
1087 matrixValue = obj.GetMatrix();
1093 bool Property::Value::Get(Rect<int32_t>& rectValue) const
1095 bool converted = false;
1097 const auto& obj = Read();
1099 if(obj.GetType() == RECTANGLE)
1101 rectValue = obj.GetRect();
1107 bool Property::Value::Get(AngleAxis& angleAxisValue) const
1109 bool converted = false;
1111 const auto& obj = Read();
1113 if(obj.GetType() == ROTATION)
1115 angleAxisValue = obj.GetAngleAxis();
1121 bool Property::Value::Get(Quaternion& quaternionValue) const
1123 bool converted = false;
1125 const auto& obj = Read();
1127 if(obj.GetType() == ROTATION)
1129 auto& angleAxis = obj.GetAngleAxis();
1130 quaternionValue = Quaternion(angleAxis.angle, angleAxis.axis);
1136 bool Property::Value::Get(std::string& stringValue) const
1138 bool converted = false;
1140 const auto& obj = Read();
1142 if(obj.GetType() == STRING)
1144 stringValue.assign(obj.GetString());
1150 bool Property::Value::Get(Property::Array& arrayValue) const
1152 bool converted = false;
1154 const auto& obj = Read();
1156 if(obj.GetType() == ARRAY)
1158 arrayValue = obj.GetArray();
1164 bool Property::Value::Get(Property::Map& mapValue) const
1166 bool converted = false;
1168 const auto& obj = Read();
1170 if(obj.GetType() == MAP)
1172 mapValue = obj.GetMap();
1178 Property::Array const* Property::Value::GetArray() const
1180 const auto& obj = Read();
1182 if(obj.GetType() == ARRAY)
1184 return obj.GetArrayPtr();
1189 Property::Array* Property::Value::GetArray()
1191 auto& obj = Write();
1193 if(obj.GetType() == ARRAY)
1195 return obj.GetArrayPtr();
1200 Property::Map const* Property::Value::GetMap() const
1202 const auto& obj = Read();
1204 if(obj.GetType() == MAP)
1206 return obj.GetMapPtr();
1211 Property::Map* Property::Value::GetMap()
1213 auto& obj = Write();
1215 if(obj.GetType() == MAP)
1217 return obj.GetMapPtr();
1222 bool Property::Value::Get(Extents& extentsValue) const
1224 bool converted = false;
1226 const auto& obj = Read();
1228 if(obj.GetType() == EXTENTS)
1230 extentsValue = obj.GetExtents();
1233 else if(obj.GetType() == VECTOR4)
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);
1246 std::ostream& operator<<(std::ostream& stream, const Property::Value& value)
1248 const auto& obj = value.Read();
1250 switch(obj.GetType())
1252 case Dali::Property::BOOLEAN:
1254 stream << obj.GetBool();
1257 case Dali::Property::FLOAT:
1259 stream << obj.GetFloat();
1262 case Dali::Property::INTEGER:
1264 stream << obj.GetInt();
1267 case Dali::Property::VECTOR2:
1269 stream << obj.GetVector2();
1272 case Dali::Property::VECTOR3:
1274 stream << obj.GetVector3();
1277 case Dali::Property::VECTOR4:
1279 stream << obj.GetVector4();
1282 case Dali::Property::MATRIX3:
1284 stream << obj.GetMatrix3();
1287 case Dali::Property::MATRIX:
1289 stream << obj.GetMatrix();
1292 case Dali::Property::RECTANGLE:
1294 stream << obj.GetRect();
1297 case Dali::Property::ROTATION:
1299 stream << obj.GetAngleAxis();
1302 case Dali::Property::STRING:
1304 stream << obj.GetString();
1307 case Dali::Property::ARRAY:
1309 stream << obj.GetArray();
1312 case Dali::Property::MAP:
1314 stream << obj.GetMap();
1317 case Dali::Property::EXTENTS:
1319 stream << obj.GetExtents();
1322 case Dali::Property::NONE:
1324 stream << "undefined type";