/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
END_TEST;
}
+int UtcDaliPropertyArrayOstream03(void)
+{
+ std::ostringstream oss;
+
+ Property::Array array1;
+ array1.PushBack(0);
+
+ Property::Array array2(std::move(array1));
+
+ oss << array1;
+ DALI_TEST_EQUALS(oss.str().compare("Array(0) = []"), 0, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliPropertyArrayCopyConstructor(void)
{
Property::Array array1;
Property::Array array2(std::move(array1));
DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION);
- // Calling any methods on array1 will debug assert
+ // Calling some methods on array1 will debug assert
const char* exceptionMessage = "Cannot use an object previously used as an r-value";
- DALI_TEST_ASSERTION(array1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.PushBack(Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Clear(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Reserve(1), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Resize(1), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Capacity(), exceptionMessage);
DALI_TEST_ASSERTION(array1[0], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Array&>(array1)[0], exceptionMessage);
- DALI_TEST_ASSERTION(Property::Array temp; array1 = temp, exceptionMessage);
-
END_TEST;
}
array2 = std::move(array1);
DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION);
- // Calling any methods on array1 will debug assert
+ // Calling some methods on array1 will debug assert
const char* exceptionMessage = "Cannot use an object previously used as an r-value";
- DALI_TEST_ASSERTION(array1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.PushBack(Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Clear(), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Reserve(1), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Resize(1), exceptionMessage);
- DALI_TEST_ASSERTION(array1.Capacity(), exceptionMessage);
DALI_TEST_ASSERTION(array1[0], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Array&>(array1)[0], exceptionMessage);
- DALI_TEST_ASSERTION(Property::Array temp; array1 = temp, exceptionMessage);
// Self std::move assignment make compile warning over gcc-13. Let we ignore the warning.
-#if (__GNUC__ >= 13)
+#if(__GNUC__ >= 13)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wself-move"
#endif
// Self assignemnt
array2 = std::move(array2);
DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION); // still works, no debug assert
-#if (__GNUC__ >= 13)
+#if(__GNUC__ >= 13)
#pragma GCC diagnostic pop
#endif
END_TEST;
}
+int UtcDaliPropertyArrayMovedArrayP1(void)
+{
+ Property::Array array1;
+ array1.PushBack(0);
+ array1.PushBack(1);
+ array1.PushBack(2);
+ DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION);
+
+ Property::Array array2(std::move(array1));
+ DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION);
+
+ // Calling some methods on array1 will debug assert
+ const char* exceptionMessage = "Cannot use an object previously used as an r-value";
+ DALI_TEST_ASSERTION(array1[0], exceptionMessage);
+ DALI_TEST_ASSERTION(const_cast<const Property::Array&>(array1)[0], exceptionMessage);
+
+ // Call some API to moved array
+ Property::Array emptyArray;
+ DALI_TEST_EQUALS(emptyArray.GetHash(), array1.GetHash(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION);
+ DALI_TEST_EQUALS(true, array1.Empty(), TEST_LOCATION);
+ array1.Clear();
+
+ // Test reserve
+ array1.Reserve(4u);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(4u, array1.Capacity(), TEST_LOCATION);
+
+ array2 = std::move(array1);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION);
+
+ // Test resize
+ array1.Resize(2u);
+ DALI_TEST_EQUALS(2u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2u, array1.Capacity(), TEST_LOCATION);
+
+ array2 = std::move(array1);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION);
+
+ // Test PushBack
+ array1.PushBack(0);
+ array1.PushBack(1);
+ array1.PushBack(2);
+ DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2, array1[2].Get<int32_t>(), TEST_LOCATION);
+
+ array2 = std::move(array1);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION);
+
+ // Test copy operator
+ DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2, array2[2].Get<int32_t>(), TEST_LOCATION);
+
+ array1 = array2;
+
+ DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2, array1[2].Get<int32_t>(), TEST_LOCATION);
+
+ array2 = std::move(array1);
+ DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION);
+
+ // Test copy moved array
+ Property::Array array3 = array1;
+ DALI_TEST_EQUALS(0u, array3.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array3.Capacity(), TEST_LOCATION);
+
+ Property::Array array4;
+ array4 = array1;
+ DALI_TEST_EQUALS(0u, array4.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array4.Capacity(), TEST_LOCATION);
+
+ // Test move operator
+ DALI_TEST_EQUALS(3u, array2.Size(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2, array2[2].Get<int32_t>(), TEST_LOCATION);
+
+ array1 = std::move(array2);
+
+ DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION);
+ DALI_TEST_EQUALS(2, array1[2].Get<int32_t>(), TEST_LOCATION);
+
+ // Test move moved array
+ DALI_TEST_EQUALS(0u, array2.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array2.Capacity(), TEST_LOCATION);
+
+ Property::Array array5 = std::move(array2);
+ DALI_TEST_EQUALS(0u, array5.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array5.Capacity(), TEST_LOCATION);
+
+ array3 = std::move(array2);
+
+ DALI_TEST_EQUALS(0u, array3.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, array3.Capacity(), TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliPropertyArrayInitializerListConstructor(void)
{
Property::Array array{1, 2, "hello"};
END_TEST;
}
+
+int UtcDaliPropertyArrayGetHashP01(void)
+{
+ tet_infoline("Check Property::Array::GetHash()");
+
+ Property::Array array;
+
+ tet_printf("Check empty array is not zero.\n");
+ auto emptyArrayHash = array.GetHash();
+
+ DALI_TEST_NOT_EQUALS(emptyArrayHash, static_cast<decltype(emptyArrayHash)>(0u), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ array.PushBack(1);
+ array.PushBack(Vector2(2.0f, 3.0f));
+ array.PushBack(4);
+
+ DALI_TEST_NOT_EQUALS(emptyArrayHash, array.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ Property::Value& lValue = array.GetElementAt(1);
+
+ auto originalHash = array.GetHash();
+
+ tet_printf("Check if l-value of some element changeness applied.\n");
+
+ DALI_TEST_EQUALS(originalHash, array.GetHash(), TEST_LOCATION);
+
+ lValue = Property::Value(Vector3(2.0f, 3.0f, 0.0f));
+ auto newHash = array.GetHash();
+
+ DALI_TEST_NOT_EQUALS(originalHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_EQUALS(array.GetElementAt(1).Get<Vector3>(), Vector3(2.0f, 3.0f, 0.0f), TEST_LOCATION);
+
+ tet_printf("Revert l-value as original value, and check it applied.\n");
+ lValue = Property::Value(Vector2(2.0f, 3.0f));
+ newHash = array.GetHash();
+
+ DALI_TEST_EQUALS(originalHash, newHash, TEST_LOCATION);
+
+ Property::Array otherArray;
+
+ otherArray.PushBack(1);
+ otherArray.PushBack(Vector2(2.0f, 3.0f));
+ otherArray.PushBack(4);
+
+ tet_printf("Check same array return same hash.\n");
+ DALI_TEST_EQUALS(originalHash, otherArray.GetHash(), TEST_LOCATION);
+
+ otherArray.Resize(4);
+
+ tet_printf("Check array with difference size return difference hash.\n");
+ DALI_TEST_NOT_EQUALS(originalHash, otherArray.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ otherArray[3] = Property::Value("5");
+ DALI_TEST_NOT_EQUALS(originalHash, otherArray.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ otherArray.Resize(3);
+
+ tet_printf("Check resized array return same hash.\n");
+ DALI_TEST_EQUALS(originalHash, otherArray.GetHash(), TEST_LOCATION);
+
+ Property::Array otherArray2;
+
+ otherArray2.PushBack(4);
+ otherArray2.PushBack(Vector2(2.0f, 3.0f));
+ otherArray2.PushBack(1);
+
+ tet_printf("Check array with difference order return difference hash.\n");
+ DALI_TEST_NOT_EQUALS(originalHash, otherArray2.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ array.Clear();
+ tet_printf("Check cleared arrayy has same value with empty array.\n");
+ DALI_TEST_EQUALS(emptyArrayHash, array.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyArrayGetHashP02(void)
+{
+ tet_infoline("Check Property::Array::GetHash() if value is Map or Array.");
+
+ Property::Array array;
+ Property::Array subArray;
+ Property::Map subMap;
+
+ subArray.PushBack(2);
+ subArray.PushBack(3);
+
+ subMap.Insert(0, "0");
+ subMap.Insert("1", 1);
+
+ array.PushBack(1);
+ array.PushBack(Vector2(2.0f, 3.0f));
+ array.PushBack(subArray);
+ array.PushBack(subMap);
+ array.PushBack(4);
+
+ auto originalHash = array.GetHash();
+
+ Property::Array* subArrayPtr = array.GetElementAt(2).GetArray();
+ Property::Map* subMapPtr = array.GetElementAt(3).GetMap();
+
+ DALI_TEST_CHECK(subArrayPtr);
+ DALI_TEST_CHECK(subMapPtr);
+
+ tet_printf("Check if l-value of some element changeness applied.\n");
+
+ subArrayPtr->PushBack(-2);
+ DALI_TEST_NOT_EQUALS(originalHash, array.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subArrayPtr->Resize(2);
+ DALI_TEST_EQUALS(originalHash, array.GetHash(), TEST_LOCATION);
+
+ subMapPtr->Insert(2, 2);
+ subMapPtr->Insert("3", "3");
+ auto newHash = array.GetHash();
+ DALI_TEST_NOT_EQUALS(originalHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subMapPtr->Remove(2);
+ DALI_TEST_NOT_EQUALS(originalHash, array.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_NOT_EQUALS(newHash, array.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subMapPtr->Remove("3");
+ DALI_TEST_EQUALS(originalHash, array.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyArrayEqualNonFloatType(void)
+{
+ tet_infoline("Check Property::Array equality if all values don't need to consider epsilon");
+
+ Property::Array array1;
+ Property::Array subArray1;
+ Property::Map subMap1;
+
+ subArray1.PushBack(2);
+ subArray1.PushBack(3);
+
+ subMap1.Insert(0, "0");
+ subMap1.Insert("1", 1);
+
+ array1.PushBack(1);
+ array1.PushBack(false);
+ array1.PushBack(subArray1);
+ array1.PushBack(subMap1);
+ array1.PushBack(4);
+
+ tet_printf("Check self-equality return true\n");
+ DALI_TEST_CHECK(array1 == array1);
+ DALI_TEST_EQUALS(array1, array1, TEST_LOCATION);
+
+ tet_printf("Generate exactly same Property::Array with array1\n");
+
+ Property::Array array2;
+ Property::Array subArray2;
+ Property::Map subMap2;
+
+ subArray2.PushBack(2);
+ subArray2.PushBack(3);
+
+ subMap2.Insert(0, "0");
+ subMap2.Insert("1", 1);
+
+ array2.PushBack(1);
+ array2.PushBack(false);
+ array2.PushBack(subArray1);
+ array2.PushBack(subMap1);
+ array2.PushBack(4);
+
+ DALI_TEST_CHECK(array1 == array2);
+ DALI_TEST_EQUALS(array1, array2, TEST_LOCATION);
+
+ tet_printf("Change array2\n");
+
+ auto oldCount = array2.Count();
+ array2.PushBack(2);
+ DALI_TEST_CHECK(array1 != array2);
+
+ tet_printf("Change array2 again\n");
+
+ array2.Resize(oldCount);
+ DALI_TEST_CHECK(array1 == array2);
+
+ tet_printf("Change array2\n");
+
+ Property::Value& value = array2.GetElementAt(1);
+ value = true;
+ DALI_TEST_CHECK(array1 != array2);
+
+ tet_printf("Change array2 again\n");
+
+ value = false;
+ DALI_TEST_CHECK(array1 == array2);
+
+ END_TEST;
+}
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Property::Map map2(std::move(map1));
DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION);
- // Calling any methods on map1 will debug assert
+ // Calling some methods on map1 will debug assert
const char* exceptionMessage = "Cannot use an object previously used as an r-value";
- DALI_TEST_ASSERTION(map1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Empty(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert((const char*)"key", Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert(std::string("key"), Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert(0, Property::Value()), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetValue(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKey(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKeyAt(1), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetPair(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKeyValue(0), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find((const char*)"key"), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(std::string("key")), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0, "key"), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find("key", Property::INTEGER), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0, Property::INTEGER), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Clear(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Merge(Property::Map()), exceptionMessage);
- DALI_TEST_ASSERTION(map1["key"], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)["key"], exceptionMessage);
- DALI_TEST_ASSERTION(map1[0], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)[0], exceptionMessage);
- DALI_TEST_ASSERTION(Property::Map temp; map1 = temp, exceptionMessage);
END_TEST;
}
map2 = std::move(map1);
DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION);
- // Calling any methods on map1 will debug assert
+ // Calling some methods on map1 will debug assert
const char* exceptionMessage = "Cannot use an object previously used as an r-value";
- DALI_TEST_ASSERTION(map1.Count(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Empty(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert((const char*)"key", Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert(std::string("key"), Property::Value()), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Insert(0, Property::Value()), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetValue(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKey(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKeyAt(1), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetPair(0), exceptionMessage);
DALI_TEST_ASSERTION(map1.GetKeyValue(0), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find((const char*)"key"), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(std::string("key")), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0, "key"), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find("key", Property::INTEGER), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Find(0, Property::INTEGER), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Clear(), exceptionMessage);
- DALI_TEST_ASSERTION(map1.Merge(Property::Map()), exceptionMessage);
- DALI_TEST_ASSERTION(map1["key"], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)["key"], exceptionMessage);
- DALI_TEST_ASSERTION(map1[0], exceptionMessage);
DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)[0], exceptionMessage);
- DALI_TEST_ASSERTION(Property::Map temp; map1 = temp, exceptionMessage);
// Self std::move assignment make compile warning over gcc-13. Let we ignore the warning.
-#if (__GNUC__ >= 13)
+#if(__GNUC__ >= 13)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wself-move"
#endif
// Self assignment
map2 = std::move(map2);
DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION); // No debug assert as nothing should happen
-#if (__GNUC__ >= 13)
+#if(__GNUC__ >= 13)
#pragma GCC diagnostic pop
#endif
END_TEST;
}
+int UtcDaliPropertyMapMovedMapP1(void)
+{
+ Property::Map map1;
+ map1["hello"] = 1;
+ map1["world"] = 2;
+ map1[10] = "DALi";
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+
+ Property::Map map2;
+ map2[10] = "DALi again";
+ DALI_TEST_EQUALS(1u, map2.Count(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION);
+
+ // Calling some methods on map1 will debug assert
+ const char* exceptionMessage = "Cannot use an object previously used as an r-value";
+ DALI_TEST_ASSERTION(map1.GetValue(0), exceptionMessage);
+ DALI_TEST_ASSERTION(map1.GetKey(0), exceptionMessage);
+ DALI_TEST_ASSERTION(map1.GetKeyAt(1), exceptionMessage);
+ DALI_TEST_ASSERTION(map1.GetPair(0), exceptionMessage);
+ DALI_TEST_ASSERTION(map1.GetKeyValue(0), exceptionMessage);
+ DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)["key"], exceptionMessage);
+ DALI_TEST_ASSERTION(const_cast<const Property::Map&>(map1)[0], exceptionMessage);
+
+ // Call some API to moved map
+ Property::Map emptyMap;
+ DALI_TEST_EQUALS(emptyMap.GetHash(), map1.GetHash(), TEST_LOCATION);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS(true, map1.Empty(), TEST_LOCATION);
+ map1.Clear();
+
+ DALI_TEST_EQUALS(false, map1.Remove(10), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, map1.Remove("hello"), TEST_LOCATION);
+
+ Property::Value* nullValuePtr = nullptr;
+ DALI_TEST_EQUALS(nullValuePtr, map1.Find(10), TEST_LOCATION);
+ DALI_TEST_EQUALS(nullValuePtr, map1.Find("hello"), TEST_LOCATION);
+ DALI_TEST_EQUALS(nullValuePtr, map1.Find(10, "hello"), TEST_LOCATION);
+ DALI_TEST_EQUALS(nullValuePtr, map1.Find(10, Property::Type::FLOAT), TEST_LOCATION);
+ DALI_TEST_EQUALS(nullValuePtr, map1.Find("hello", Property::Type::FLOAT), TEST_LOCATION);
+
+ // Test Insert
+ map1["hello"] = 1;
+ map1.Insert("world", 2);
+ map1[10] = "DALi";
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS("DALi", map1.Find(10)->Get<std::string>(), TEST_LOCATION);
+ DALI_TEST_EQUALS(1, map1.Find("hello")->Get<int32_t>(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test Insert 2 (Index key first)
+ map1[10] = "DALi";
+ map1["hello"] = 1;
+ map1.Insert("world", 2);
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS("DALi", map1.Find(10)->Get<std::string>(), TEST_LOCATION);
+ DALI_TEST_EQUALS(1, map1.Find("hello")->Get<int32_t>(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test Insert 3 (Insert key first)
+ map1.Insert(4, 2);
+ map1[10] = "DALi";
+ map1["hello"] = 1;
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS("DALi", map1.Find(10)->Get<std::string>(), TEST_LOCATION);
+ DALI_TEST_EQUALS(1, map1.Find("hello")->Get<int32_t>(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test Insert 4 (Insert string first)
+ map1.Insert("world", 2);
+ map1[10] = "DALi";
+ map1["hello"] = 1;
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+ DALI_TEST_EQUALS("DALi", map1.Find(10)->Get<std::string>(), TEST_LOCATION);
+ DALI_TEST_EQUALS(1, map1.Find("hello")->Get<int32_t>(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test Merge
+ map1.Merge(map2);
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test copy operator
+ DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION);
+
+ map1 = map2;
+
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+
+ map2 = std::move(map1);
+ DALI_TEST_EQUALS(0u, map1.Count(), TEST_LOCATION);
+
+ // Test copy moved map
+ Property::Map map3 = map1;
+ DALI_TEST_EQUALS(0u, map3.Count(), TEST_LOCATION);
+
+ Property::Map map4;
+ map4 = map1;
+ DALI_TEST_EQUALS(0u, map4.Count(), TEST_LOCATION);
+
+ // Test move operator
+ DALI_TEST_EQUALS(3u, map2.Count(), TEST_LOCATION);
+
+ map1 = std::move(map2);
+
+ DALI_TEST_EQUALS(3u, map1.Count(), TEST_LOCATION);
+
+ // Test move moved map
+ DALI_TEST_EQUALS(0u, map2.Count(), TEST_LOCATION);
+ Property::Map map5 = std::move(map2);
+
+ DALI_TEST_EQUALS(0u, map5.Count(), TEST_LOCATION);
+
+ map3 = std::move(map2);
+
+ DALI_TEST_EQUALS(0u, map3.Count(), TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliPropertyMapConstOperator(void)
{
Property::Map map;
END_TEST;
}
+int UtcDaliPropertyMapOstream03(void)
+{
+ std::ostringstream oss;
+
+ Property::Map map;
+ map.Insert(100, 9);
+
+ Property::Map map2(std::move(map));
+
+ oss << map;
+ DALI_TEST_EQUALS(oss.str().compare("Map(0) = {}"), 0, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliPropertyKeyConstructorP(void)
{
Property::Key key1("aKey");
END_TEST;
}
+
+int UtcDaliPropertyMapGetHashP01(void)
+{
+ tet_infoline("Check Property::Map::GetHash()");
+
+ Property::Map map;
+
+ tet_printf("Check empty map is not zero.\n");
+ auto emptyMapHash = map.GetHash();
+
+ DALI_TEST_NOT_EQUALS(emptyMapHash, static_cast<decltype(emptyMapHash)>(0u), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ map.Insert(1, 1);
+ map.Insert(2, Vector2(2.0f, 3.0f));
+ map.Insert("3", 4);
+
+ DALI_TEST_NOT_EQUALS(emptyMapHash, map.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ Property::Value* lValuePtr = map.Find(2);
+
+ auto originalHash = map.GetHash();
+
+ tet_printf("Check if l-value of some element changeness applied.\n");
+
+ DALI_TEST_EQUALS(originalHash, map.GetHash(), TEST_LOCATION);
+
+ (*lValuePtr) = Property::Value(Vector3(2.0f, 3.0f, 0.0f));
+ auto newHash = map.GetHash();
+
+ DALI_TEST_NOT_EQUALS(originalHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_EQUALS(map.Find(2)->Get<Vector3>(), Vector3(2.0f, 3.0f, 0.0f), TEST_LOCATION);
+
+ tet_printf("Revert l-value as original value, and check it applied.\n");
+ (*lValuePtr) = Property::Value(Vector2(2.0f, 3.0f));
+ newHash = map.GetHash();
+
+ DALI_TEST_EQUALS(originalHash, newHash, TEST_LOCATION);
+
+ Property::Map otherMap;
+
+ otherMap.Insert(1, 1);
+ otherMap.Insert(2, Vector2(2.0f, 3.0f));
+ otherMap.Insert("3", 4);
+
+ tet_printf("Check same map return same hash.\n");
+ DALI_TEST_EQUALS(originalHash, otherMap.GetHash(), TEST_LOCATION);
+
+ Property::Value value = otherMap[44]; ///< Dummy action to create empty element.
+
+ tet_printf("Check map with difference size return difference hash.\n");
+ DALI_TEST_NOT_EQUALS(originalHash, otherMap.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ otherMap[44] = Property::Value("44");
+ DALI_TEST_NOT_EQUALS(originalHash, otherMap.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ otherMap.Remove(44);
+
+ tet_printf("Check removed map return same hash.\n");
+ DALI_TEST_EQUALS(originalHash, otherMap.GetHash(), TEST_LOCATION);
+
+ Property::Map otherMap2;
+
+ otherMap2.Insert(2, Vector2(2.0f, 3.0f));
+ otherMap2.Insert(1, 1);
+ otherMap2.Insert("3", 4);
+
+ tet_printf("Check map with difference order return same hash.\n");
+ DALI_TEST_EQUALS(originalHash, otherMap2.GetHash(), TEST_LOCATION);
+
+ map.Clear();
+ tet_printf("Check cleared map has same value with empty map.\n");
+ DALI_TEST_EQUALS(emptyMapHash, map.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyMapGetHashP02(void)
+{
+ tet_infoline("Check Property::Map::GetHash() if value is Map or Array.");
+
+ Property::Map map;
+ Property::Array subArray;
+ Property::Map subMap;
+
+ subArray.PushBack(2);
+ subArray.PushBack(3);
+
+ subMap.Insert(0, "0");
+ subMap.Insert("1", 1);
+
+ map.Insert(1, 1);
+ map.Insert(2, Vector2(2.0f, 3.0f));
+ map.Insert(3, subArray);
+ map.Insert("4", subMap);
+ map.Insert("5", 4);
+
+ auto originalHash = map.GetHash();
+
+ Property::Array* subArrayPtr = map.Find(3)->GetArray();
+ Property::Map* subMapPtr = map.Find("4")->GetMap();
+
+ DALI_TEST_CHECK(subArrayPtr);
+ DALI_TEST_CHECK(subMapPtr);
+
+ tet_printf("Check if l-value of some element changeness applied.\n");
+
+ subArrayPtr->PushBack(-2);
+ DALI_TEST_NOT_EQUALS(originalHash, map.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subArrayPtr->Resize(2);
+ DALI_TEST_EQUALS(originalHash, map.GetHash(), TEST_LOCATION);
+
+ subMapPtr->Insert(2, 2);
+ subMapPtr->Insert("3", "3");
+ auto newHash = map.GetHash();
+ DALI_TEST_NOT_EQUALS(originalHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subMapPtr->Remove(2);
+ DALI_TEST_NOT_EQUALS(originalHash, map.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_NOT_EQUALS(newHash, map.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ subMapPtr->Remove("3");
+ DALI_TEST_EQUALS(originalHash, map.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyMapEqualNonFloatType(void)
+{
+ tet_infoline("Check Property::Map equality if all values don't need to consider epsilon");
+
+ Property::Map map1;
+ Property::Array subArray1;
+ Property::Map subMap1;
+
+ subArray1.PushBack(2);
+ subArray1.PushBack(3);
+
+ subMap1.Insert(0, "0");
+ subMap1.Insert("1", 1);
+
+ map1.Insert(1, 1);
+ map1.Insert(2, false);
+ map1.Insert(3, subArray1);
+ map1.Insert("4", subMap1);
+ map1.Insert("5", 4);
+
+ tet_printf("Check self-equality return true\n");
+ DALI_TEST_CHECK(map1 == map1);
+ DALI_TEST_EQUALS(map1, map1, TEST_LOCATION);
+
+ tet_printf("Generate exactly same Property::Map with map1\n");
+
+ Property::Map map2;
+ Property::Array subArray2;
+ Property::Map subMap2;
+
+ subArray2.PushBack(2);
+ subArray2.PushBack(3);
+
+ subMap2.Insert("1", 1);
+ subMap2.Insert(0, "0");
+
+ map2.Insert(3, subArray1);
+ map2.Insert(2, false);
+ map2.Insert(1, 1);
+ map2.Insert("5", 4);
+ map2.Insert("4", subMap1);
+
+ DALI_TEST_CHECK(map1 == map2);
+ DALI_TEST_EQUALS(map1, map2, TEST_LOCATION);
+
+ tet_printf("Change map2\n");
+
+ map2.Insert(999, "999");
+ DALI_TEST_CHECK(map1 != map2);
+
+ tet_printf("Change map2 again\n");
+
+ map2.Remove(999);
+ DALI_TEST_CHECK(map1 == map2);
+
+ tet_printf("Change map2\n");
+
+ Property::Value* valuePtr = map2.Find(2);
+ *valuePtr = true;
+ DALI_TEST_CHECK(map1 != map2);
+
+ tet_printf("Change map2 again\n");
+
+ *valuePtr = false;
+ DALI_TEST_CHECK(map1 == map2);
+
+ END_TEST;
+}
DALI_TEST_EQUALS(3u, array.Size(), TEST_LOCATION);
Property::Value value(std::move(array));
- DALI_TEST_ASSERTION(array.Size(), "Cannot use an object previously used as an r-value"); // Our local variable should become invalid
+ DALI_TEST_EQUALS(0u, array.Size(), TEST_LOCATION);
Property::Array* arrayPtr = value.GetArray();
DALI_TEST_CHECK(arrayPtr);
DALI_TEST_EQUALS(3u, map.Count(), TEST_LOCATION);
Property::Value value(std::move(map));
- DALI_TEST_ASSERTION(map.Count(), "Cannot use an object previously used as an r-value"); // Our local variable should become invalid
+ DALI_TEST_EQUALS(0u, map.Count(), TEST_LOCATION);
Property::Map* mapPtr = value.GetMap();
DALI_TEST_CHECK(mapPtr);
DALI_TEST_NOT_EQUALS(value4, value6, Math::MACHINE_EPSILON_100, TEST_LOCATION);
DALI_TEST_NOT_EQUALS(value5, value6, Math::MACHINE_EPSILON_100, TEST_LOCATION);
- // TODO : Currently array comparision not implemented.
- // If we impelemnt array comparision, replace below line.
- // DALI_TEST_EQUALS(value1, value2, TEST_LOCATION);
- DALI_TEST_NOT_EQUALS(value1, value2, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ // TODO : Currently array comparision with epsilon was not implemented.
+ // For safety, let we compare only if hash value is same
+ if(value1.GetHash() == value2.GetHash())
+ {
+ DALI_TEST_EQUALS(value1, value2, TEST_LOCATION);
+ }
+ else
+ {
+ tet_printf("Hash value not mathed. But it should return true exceptually. We need to implement it\n");
+ }
END_TEST;
}
DALI_TEST_NOT_EQUALS(value4, value6, Math::MACHINE_EPSILON_100, TEST_LOCATION);
DALI_TEST_NOT_EQUALS(value5, value6, Math::MACHINE_EPSILON_100, TEST_LOCATION);
- // TODO : Currently map comparision not implemented.
- // If we impelemnt map comparision, replace below line.
- // DALI_TEST_EQUALS(value1, value2, TEST_LOCATION);
- DALI_TEST_NOT_EQUALS(value1, value2, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ // TODO : Currently map comparision with epsilon was not implemented.
+ // For safety, let we compare only if hash value is same
+ if(value1.GetHash() == value2.GetHash())
+ {
+ DALI_TEST_EQUALS(value1, value2, TEST_LOCATION);
+ }
+ else
+ {
+ tet_printf("Hash value not mathed. But it should return true exceptually. We need to implement it\n");
+ }
END_TEST;
}
END_TEST;
}
+
+int UtcDaliPropertyValueGetHashP01(void)
+{
+ tet_infoline("Check Property::Value::GetHash() type equality.");
+
+ const float a[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f};
+ const float b[] = {16.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 1.0f};
+ Property::Value valueList[] =
+ {
+ Property::Value(static_cast<bool>(true)),
+ Property::Value(static_cast<float>(7.0f)),
+ Property::Value(static_cast<int32_t>(32)),
+ Property::Value(Vector2(1.0f, 2.0f)),
+ Property::Value(Vector3(1.1f, 2.2f, 3.3f)),
+ Property::Value(Vector4(1.2f, 2.1f, 3.4f, 4.3f)),
+ Property::Value(Matrix3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f)),
+ Property::Value(Matrix(a)),
+ Property::Value(Rect<int32_t>(3, 2, 5, 4)),
+ Property::Value(AngleAxis(Radian(2.0f), Vector3(0.0f, 1.0f, 0.0f))),
+ Property::Value(std::string("Hello, World!")),
+ Property::Value(Extents(8, 4, 2, 5)),
+ Property::Value(Property::Array({1.0f, Vector2(2.0f, 3.0f), static_cast<int32_t>(4), std::string("Five"), Matrix(a)})),
+ Property::Value(Property::Map({{1, 1.0f}, {"2", Vector4(2.0f, 3.0f, 4.0f, 5.0f)}, {3, static_cast<int32_t>(6)}, {4, std::string("Lucky")}})),
+ };
+ Property::Value otherValueList[] =
+ {
+ Property::Value(static_cast<bool>(false)),
+ Property::Value(static_cast<float>(1.0f)),
+ Property::Value(static_cast<int32_t>(4)),
+ Property::Value(Vector2(2.0f, 1.0f)),
+ Property::Value(Vector3(2.2f, 1.1f, 3.3f)),
+ Property::Value(Vector4(2.1f, 1.2f, 3.4f, 4.3f)),
+ Property::Value(Matrix3(7.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f)),
+ Property::Value(Matrix(b)),
+ Property::Value(Rect<int32_t>(2, 3, 4, 5)),
+ Property::Value(AngleAxis(Radian(20.0f), Vector3(0.0f, 1.0f, 0.0f))),
+ Property::Value(std::string("Hell, o, World!")),
+ Property::Value(Extents(4, 8, 5, 2)),
+ Property::Value(Property::Array({5.0f, Vector2(4.0f, 3.0f), static_cast<int32_t>(2), std::string("ONE"), Matrix(b)})),
+ Property::Value(Property::Map({{"1", 5.0f}, {2, Vector4(4.0f, 3.0f, 2.0f, 1.0f)}, {"three", static_cast<int32_t>(0)}, {1, std::string("-1")}})),
+ };
+ const int valueCount = sizeof(valueList) / sizeof(valueList[0]);
+
+ // Compare Value and HashValue
+ for(int i = 0; i < valueCount; ++i)
+ {
+ // Check self comparision
+ DALI_TEST_EQUALS(valueList[i].GetHash(), valueList[i].GetHash(), TEST_LOCATION);
+ // Check same value comparision
+ Property::Value copiedValue = valueList[i];
+ DALI_TEST_EQUALS(valueList[i].GetHash(), copiedValue.GetHash(), TEST_LOCATION);
+ // Check not equal value comparision
+ DALI_TEST_NOT_EQUALS(valueList[i].GetHash(), otherValueList[i].GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ // Check empty type value
+ DALI_TEST_NOT_EQUALS(valueList[i].GetHash(), Property::Value().GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ }
+
+ // Compare with empty type.
+ auto emptyValueHash = Property::Value().GetHash();
+
+ DALI_TEST_EQUALS(Property::Value().GetHash(), emptyValueHash, TEST_LOCATION);
+ DALI_TEST_NOT_EQUALS(Property::Value().GetHash(), static_cast<decltype(emptyValueHash)>(0u), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyValueGetHashP02(void)
+{
+ tet_infoline("Check Property::Value::GetHash() equality for Property::Array.");
+
+ const float a[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f};
+ Property::Value value = Property::Value(Property::Array({1.0f, Vector2(2.0f, 3.0f), static_cast<int32_t>(4), std::string("Five"), Matrix(a)}));
+
+ const auto originHash = value.GetHash();
+
+ Property::Array* arrayPtr = value.GetArray();
+
+ tet_printf("Check value's hash is not equal with array itself's hash.\n");
+ DALI_TEST_CHECK(arrayPtr);
+ DALI_TEST_NOT_EQUALS(originHash, arrayPtr->GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ Property::Array copiedArray = *arrayPtr;
+ Property::Value copiedValue = Property::Value(copiedArray);
+
+ // Compare with copied array.
+ DALI_TEST_EQUALS(originHash, copiedValue.GetHash(), TEST_LOCATION);
+
+ arrayPtr->PushBack(Property::Value(6.0f));
+
+ const auto newHash = value.GetHash();
+
+ DALI_TEST_NOT_EQUALS(originHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ // Add same property value to copied array
+ copiedArray.PushBack(Property::Value(6.0f));
+ Property::Value copiedValue2 = Property::Value(copiedArray);
+
+ // Compare with copied array.
+ DALI_TEST_NOT_EQUALS(copiedValue.GetHash(), copiedValue2.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_EQUALS(newHash, copiedValue2.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPropertyValueGetHashP03(void)
+{
+ tet_infoline("Check Property::Value::GetHash() equality for Property::Map.");
+
+ const float a[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f};
+ Property::Value value = Property::Value(Property::Map({{0, 1.0f}, {1, Vector2(2.0f, 3.0f)}, {"2", static_cast<int32_t>(4)}, {"3", std::string("Five")}, {4, Matrix(a)}}));
+
+ const auto originHash = value.GetHash();
+
+ Property::Map* mapPtr = value.GetMap();
+
+ tet_printf("Check value's hash is not equal with map itself's hash.\n");
+ DALI_TEST_CHECK(mapPtr);
+ DALI_TEST_NOT_EQUALS(originHash, mapPtr->GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ Property::Map copiedMap = *mapPtr;
+ Property::Value copiedValue = Property::Value(copiedMap);
+
+ // Compare with copied map.
+ DALI_TEST_EQUALS(originHash, copiedValue.GetHash(), TEST_LOCATION);
+
+ mapPtr->Insert(5, Property::Value(5));
+ mapPtr->Insert(6, Property::Value(std::string("6")));
+ mapPtr->Insert("7", Property::Value(7));
+ mapPtr->Insert("8", Property::Value(std::string("8")));
+
+ const auto newHash = value.GetHash();
+
+ DALI_TEST_NOT_EQUALS(originHash, newHash, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+ // Add same property value to copied map, seperated order
+ copiedMap.Insert(6, Property::Value(std::string("6")));
+ copiedMap.Insert("8", Property::Value(std::string("8")));
+ copiedMap.Insert(5, Property::Value(5));
+ copiedMap.Insert("7", Property::Value(7));
+ Property::Value copiedValue2 = Property::Value(copiedMap);
+
+ // Compare with copied array.
+ DALI_TEST_NOT_EQUALS(copiedValue.GetHash(), copiedValue2.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION);
+ DALI_TEST_EQUALS(newHash, copiedValue2.GetHash(), TEST_LOCATION);
+
+ END_TEST;
+}
// CLASS HEADER
#include <dali/devel-api/common/hash.h>
-namespace Dali
-{
-namespace //unnamed namespace
-{
-/*
- * djb2 (http://www.cse.yorku.ca/~oz/hash.html)
- */
-
-inline void HashString(const char* string, std::size_t& hash)
-{
- while(int c = *string++)
- {
- hash = hash * 33 + c;
- }
-}
-
-inline void HashString(const char* string, std::size_t& hash, char terminator)
-{
- char c;
- while((c = *string++) && c != terminator)
- {
- hash = hash * 33 + c;
- }
-}
-
-inline void HashStringView(const std::string_view& string, std::size_t& hash)
-{
- for(auto c : string)
- {
- hash = hash * 33 + c;
- }
-}
-
-inline void HashStringView(const std::string_view& string, std::size_t& hash, char terminator)
-{
- for(auto c : string)
- {
- if(c == terminator)
- {
- break;
- }
- hash = hash * 33 + static_cast<std::size_t>(c);
- }
-}
-
-inline void HashBuffer(const std::vector<std::uint8_t>& buffer, std::size_t& hash)
-{
- for(const auto& c : buffer)
- {
- hash = hash * 33 + c;
- }
-}
+// INTERNAL INCLUDES
+#include <dali/internal/common/hash-utils.h>
-inline void HashBuffer(const Dali::Vector<std::uint8_t>& buffer, std::size_t& hash)
+namespace Dali
{
- for(const auto& c : buffer)
- {
- hash = hash * 33 + c;
- }
-}
-
-} // unnamed namespace
-
std::size_t CalculateHash(const std::string& toHash)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashString(toHash.c_str(), hash);
+ Dali::Internal::HashUtils::HashString(toHash.c_str(), hash);
return hash;
}
std::size_t CalculateHash(const std::string& toHash, char terminator)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashString(toHash.c_str(), hash, terminator);
+ Dali::Internal::HashUtils::HashString(toHash.c_str(), hash, terminator);
return hash;
}
std::size_t CalculateHash(const std::string& string1, const std::string& string2)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashString(string1.c_str(), hash);
- HashString(string2.c_str(), hash);
+ Dali::Internal::HashUtils::HashString(string1.c_str(), hash);
+ Dali::Internal::HashUtils::HashString(string2.c_str(), hash);
return hash;
}
std::size_t CalculateHash(const std::string_view& toHash)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashStringView(toHash, hash);
+ Dali::Internal::HashUtils::HashStringView(toHash, hash);
return hash;
}
std::size_t CalculateHash(const std::string_view& toHash, char terminator)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashStringView(toHash, hash, terminator);
+ Dali::Internal::HashUtils::HashStringView(toHash, hash, terminator);
return hash;
}
std::size_t CalculateHash(const std::string_view& string1, const std::string_view& string2)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashStringView(string1, hash);
- HashStringView(string2, hash);
+ Dali::Internal::HashUtils::HashStringView(string1, hash);
+ Dali::Internal::HashUtils::HashStringView(string2, hash);
return hash;
}
std::size_t CalculateHash(const std::vector<std::uint8_t>& toHash)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashBuffer(toHash, hash);
+ Dali::Internal::HashUtils::HashBuffer(toHash, hash);
return hash;
}
std::size_t CalculateHash(const Dali::Vector<std::uint8_t>& toHash)
{
- std::size_t hash(INITIAL_HASH_VALUE);
+ std::size_t hash(Dali::Internal::HashUtils::INITIAL_HASH_VALUE);
- HashBuffer(toHash, hash);
+ Dali::Internal::HashUtils::HashBuffer(toHash, hash);
return hash;
}
// EXTERNAL INCLUDES
#include <string>
#include <string_view>
-#include <vector>
//INTERNAL INCLUDES
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
namespace Dali
{
-enum
-{
- INITIAL_HASH_VALUE = 5381
-};
-
/**
* @brief Create a hash code for a string
* @param toHash string to hash
--- /dev/null
+#ifndef DALI_INTERNAL_HASH_UTILS_H
+#define DALI_INTERNAL_HASH_UTILS_H
+
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <string_view>
+
+//INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali::Internal::HashUtils
+{
+constexpr std::size_t INITIAL_HASH_VALUE = 5381;
+
+/*
+ * djb2 (http://www.cse.yorku.ca/~oz/hash.html)
+ */
+
+[[maybe_unused]] inline std::size_t HashString(const char* string, std::size_t& hash)
+{
+ while(int c = *string++)
+ {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
+[[maybe_unused]] inline std::size_t HashString(const char* string, std::size_t& hash, char terminator)
+{
+ char c;
+ while((c = *string++) && c != terminator)
+ {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
+[[maybe_unused]] inline std::size_t HashStringView(const std::string_view& string, std::size_t& hash)
+{
+ for(auto c : string)
+ {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
+[[maybe_unused]] inline std::size_t HashStringView(const std::string_view& string, std::size_t& hash, char terminator)
+{
+ for(auto c : string)
+ {
+ if(c == terminator)
+ {
+ break;
+ }
+ hash = hash * 33 + static_cast<std::size_t>(c);
+ }
+ return hash;
+}
+
+[[maybe_unused]] inline std::size_t HashBuffer(const std::vector<std::uint8_t>& buffer, std::size_t& hash)
+{
+ for(const auto& c : buffer)
+ {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
+[[maybe_unused]] inline std::size_t HashBuffer(const Dali::Vector<std::uint8_t>& buffer, std::size_t& hash)
+{
+ for(const auto& c : buffer)
+ {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
+template<typename T>
+[[maybe_unused]] inline std::size_t HashRawBuffer(const T* buffer, std::size_t bufferSize, std::size_t& hash)
+{
+ if constexpr(sizeof(T) == 1u)
+ {
+ while(bufferSize--)
+ {
+ hash = hash * 33 + *(buffer++);
+ }
+ return hash;
+ }
+ else
+ {
+ return HashRawBuffer(reinterpret_cast<const std::uint8_t*>(buffer), sizeof(T) * bufferSize, hash);
+ }
+}
+
+template<typename T>
+[[maybe_unused]] inline std::size_t HashRawValue(const T& value, std::size_t& hash)
+{
+ return HashRawBuffer(reinterpret_cast<const std::uint8_t*>(&value), sizeof(T), hash);
+}
+
+} // namespace Dali::Internal::HashUtils
+
+#endif // DALI_INTERNAL_HASH_UTILS_H
#define DALI_INTERNAL_PROPERTY_INPUT_IMPL_H
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// INTERNAL INCLUDES
#include <dali/internal/common/buffer-index.h>
+#include <dali/internal/common/hash-utils.h>
#include <dali/public-api/math/matrix.h>
#include <dali/public-api/math/matrix3.h>
#include <dali/public-api/math/quaternion.h>
#include <dali/public-api/math/vector4.h>
#include <dali/public-api/object/property-input.h>
-#if defined(ANDROID) || defined(WIN32) || defined(__APPLE__)
-namespace std
-{
-uint64_t _Hash_bytes(const void* bytes, uint64_t size, uint64_t seed);
-
-}
-#endif
-
namespace Dali
{
namespace Internal
return false;
}
- std::uint64_t Hash(BufferIndex bufferIndex, uint64_t seed) const
+ std::size_t Hash(BufferIndex bufferIndex, std::size_t seed) const
{
switch(GetType())
{
case Property::BOOLEAN:
{
- return std::_Hash_bytes(&GetBoolean(bufferIndex), sizeof(bool), seed);
+ return Dali::Internal::HashUtils::HashRawValue(GetBoolean(bufferIndex), seed);
}
case Property::INTEGER:
{
- return std::_Hash_bytes(&GetInteger(bufferIndex), sizeof(int), seed);
+ return Dali::Internal::HashUtils::HashRawValue(GetInteger(bufferIndex), seed);
}
case Property::FLOAT:
{
- return std::_Hash_bytes(&GetFloat(bufferIndex), sizeof(float), seed);
+ return Dali::Internal::HashUtils::HashRawValue(GetFloat(bufferIndex), seed);
}
case Property::VECTOR2:
{
- return std::_Hash_bytes(&GetVector2(bufferIndex), sizeof(Vector2), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetVector2(bufferIndex).AsFloat(), 2, seed);
}
case Property::VECTOR3:
{
- return std::_Hash_bytes(&GetVector3(bufferIndex), sizeof(Vector3), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetVector3(bufferIndex).AsFloat(), 3, seed);
}
case Property::VECTOR4:
{
- return std::_Hash_bytes(&GetVector4(bufferIndex), sizeof(Vector4), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetVector4(bufferIndex).AsFloat(), 4, seed);
}
case Property::ROTATION:
{
- return std::_Hash_bytes(&GetQuaternion(bufferIndex), sizeof(Quaternion), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetQuaternion(bufferIndex).AsVector().AsFloat(), 4, seed);
}
case Property::MATRIX:
{
- return std::_Hash_bytes(&GetMatrix(bufferIndex), sizeof(Matrix), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetMatrix(bufferIndex).AsFloat(), 16, seed);
}
case Property::MATRIX3:
{
- return std::_Hash_bytes(&GetMatrix3(bufferIndex), sizeof(Matrix3), seed);
+ return Dali::Internal::HashUtils::HashRawBuffer<float>(GetMatrix3(bufferIndex).AsFloat(), 9, seed);
}
default:
#include <dali/internal/update/manager/update-manager.h>
#include <dali/public-api/rendering/vertex-buffer.h>
-#if defined(ANDROID) || defined(WIN32) || defined(__APPLE__)
-namespace std
-{
-uint64_t _Hash_bytes(const void* bytes, uint64_t size, uint64_t seed)
-{
- for(uint64_t i = 0; i < size; i++)
- {
- seed = seed * 31 + reinterpret_cast<const unsigned char*>(bytes)[i];
- }
-
- return seed;
-}
-} // namespace std
-#endif
-
namespace Dali
{
namespace Internal
*/
struct PartialRenderingData
{
- Matrix matrix{}; /// Model-view matrix
- Vector4 color{}; /// Color
- Vector4 updatedPositionSize{}; /// Updated position/size (x, y, width, height)
- Vector3 size{}; /// Size
- uint32_t hash{0u}; /// Last frame's hash
+ Matrix matrix{}; /// Model-view matrix
+ Vector4 color{}; /// Color
+ Vector4 updatedPositionSize{}; /// Updated position/size (x, y, width, height)
+ Vector3 size{}; /// Size
+ std::size_t hash{0u}; /// Last frame's hash
bool mVisible : 1; /// Visible state. It is depends on node's visibility (Not hashed)
bool mUpdated : 1; /// IsUpdated return true at this frame. Will be reset at UpdateNodes time. (Not hashed)
*/
void CalculateHash()
{
- hash = Dali::INITIAL_HASH_VALUE;
- AddToHash(hash, &matrix, sizeof(decltype(matrix)));
- AddToHash(hash, &color, sizeof(decltype(color)));
- AddToHash(hash, &updatedPositionSize, sizeof(decltype(updatedPositionSize)));
- AddToHash(hash, &size, sizeof(decltype(size)));
+ hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+ Dali::Internal::HashUtils::HashRawBuffer<float>(matrix.AsFloat(), 16, hash);
+ Dali::Internal::HashUtils::HashRawBuffer<float>(color.AsFloat(), 4, hash);
+ Dali::Internal::HashUtils::HashRawBuffer<float>(updatedPositionSize.AsFloat(), 4, hash);
+ Dali::Internal::HashUtils::HashRawBuffer<float>(size.AsFloat(), 3, hash);
}
/**
{
mUpdateDecay = Decay::EXPIRED;
}
-
-private:
- void AddToHash(uint32_t& aHash, void* el, size_t numBytes)
- {
- uint8_t* elBytes = static_cast<uint8_t*>(el);
- for(size_t i = 0; i < numBytes; ++i)
- {
- aHash = aHash * 33 + *elBytes++;
- }
- }
};
} // namespace Dali::Internal::SceneGraph
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// CLASS HEADER
#include <dali/public-api/object/property-array.h>
+// EXTERNAL INCLUDES
+#include <limits>
+
// INTERNAL INCLUDES
+#include <dali/internal/common/hash-utils.h>
#include <dali/public-api/common/vector-wrapper.h>
namespace Dali
{
namespace
{
-}; // unnamed namespace
+constexpr std::size_t NOT_HASHED = 0u;
+constexpr std::size_t ALWAYS_REHASH = std::numeric_limits<std::size_t>::max();
+} // namespace
struct Property::Array::Impl
{
typedef std::vector<Value> Array;
+public:
+ std::size_t GetHash() const
+ {
+ std::size_t hash = mHash;
+ if(hash == ALWAYS_REHASH || hash == NOT_HASHED)
+ {
+ hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+
+ for(const auto& iter : mArray)
+ {
+ // Use ordered hash operation.
+ Dali::Internal::HashUtils::HashRawValue(iter.GetHash(), hash);
+ }
+
+ if(mHash != ALWAYS_REHASH)
+ {
+ mHash = hash;
+ }
+ }
+ return hash;
+ }
+
+public:
Array mArray;
+
+ mutable std::size_t mHash{NOT_HASHED};
};
Property::Array::Array()
Property::Array::Array(const Property::Array& other)
: mImpl(new Impl)
{
- mImpl->mArray = other.mImpl->mArray;
+ if(DALI_LIKELY(other.mImpl))
+ {
+ mImpl->mArray = other.mImpl->mArray;
+ // Keep mHash as NOT_HASHED.
+ }
}
Property::Array::Array(Property::Array&& other) noexcept
Property::Array::SizeType Property::Array::Count() const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- return mImpl->mArray.size();
+ return DALI_LIKELY(mImpl) ? mImpl->mArray.size() : 0;
}
void Property::Array::PushBack(const Value& value)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED)
+ {
+ // Use ordered hash operation.
+ Dali::Internal::HashUtils::HashRawValue(value.GetHash(), mImpl->mHash);
+ }
mImpl->mArray.push_back(value);
}
void Property::Array::Clear()
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- mImpl->mArray.clear();
+ if(DALI_LIKELY(mImpl))
+ {
+ mImpl->mArray.clear();
+ mImpl->mHash = NOT_HASHED;
+ }
}
void Property::Array::Reserve(SizeType size)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
mImpl->mArray.reserve(size);
}
void Property::Array::Resize(SizeType size)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- mImpl->mArray.resize(size);
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mArray.size() != size)
+ {
+ mImpl->mArray.resize(size);
+
+ // Just reset hash as zero.
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ mImpl->mHash = NOT_HASHED;
+ }
+ }
}
Property::Array::SizeType Property::Array::Capacity()
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- return mImpl->mArray.capacity();
+ return DALI_LIKELY(mImpl) ? mImpl->mArray.capacity() : 0;
}
const Property::Value& Property::Array::operator[](SizeType index) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
// Note says no bounds checking is performed so we don't need to verify mImpl as Count() will return 0 anyway
return mImpl->mArray[index];
Property::Value& Property::Array::operator[](SizeType index)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
+
+ // Mark as we should rehash always. (Since new value might be changed by application side anytime.)
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ mImpl->mHash = ALWAYS_REHASH;
+ }
// Note says no bounds checking is performed so we don't need to verify mImpl as Count() will return 0 anyway
return mImpl->mArray[index];
Property::Array& Property::Array::operator=(const Property::Array& other)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
if(this != &other)
{
- mImpl->mArray = other.mImpl->mArray;
+ if(DALI_UNLIKELY(other.mImpl == nullptr))
+ {
+ Clear();
+ }
+ else
+ {
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+ mImpl->mArray = other.mImpl->mArray;
+ mImpl->mHash = other.mImpl->mHash;
+ }
}
return *this;
}
return *this;
}
+bool Property::Array::operator==(const Property::Array& rhs) const
+{
+ // TODO : Need to check epsilon for float comparison in future. For now, just compare hash value and count.
+ return Count() == rhs.Count() && GetHash() == rhs.GetHash();
+}
+
+std::size_t Property::Array::GetHash() const
+{
+ return DALI_LIKELY(mImpl) ? mImpl->GetHash() : Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+}
+
std::ostream& operator<<(std::ostream& stream, const Property::Array& array)
{
stream << "Array(" << array.Count() << ") = [";
- for(Property::Array::SizeType i = 0; i < array.Count(); ++i)
+
+ if(DALI_LIKELY(array.mImpl))
{
- if(i > 0)
+ for(Property::Array::SizeType i = 0; i < array.Count(); ++i)
+ {
+ if(i > 0)
+ {
+ stream << ", ";
+ }
+ stream << array.GetElementAt(i);
+ }
+
+ if(array.mImpl->mHash != NOT_HASHED)
{
- stream << ", ";
+ stream << "(hash=" << array.mImpl->mHash << ")";
}
- stream << array.GetElementAt(i);
}
+
stream << "]";
return stream;
#define DALI_PROPERTY_ARRAY_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
Array& operator=(Array&& other) noexcept;
+ /**
+ * @brief Equality operator.
+ *
+ * @SINCE_2_3.54
+ * @param[in] rhs A reference for comparison
+ * @return True if equal type and equal value.
+ */
+ bool operator==(const Array& rhs) const;
+
+ /**
+ * @brief Inequality operator.
+ *
+ * @SINCE_2_3.54
+ * @param[in] rhs A reference for comparison
+ * @return True if not equal
+ */
+ bool operator!=(const Array& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ /**
+ * @brief Get hash value of the array.
+ *
+ * @note The order of key/value pairs is considered.
+ * For example, Array({1, 2}) and Array({2, 1}) might not have same hash value.
+ * And the type of Property::Value is considered.
+ * For example, Array({1}) and Array({1.0f}) might not have same hash value.
+ *
+ * @warning Hash might spend O(N) per each call.
+ * @warning Hash don't consider floating point precision. So even if two values equality return true,
+ * they can have different hash value.
+ * @code
+ * Property::Array v1({1.0f}});
+ * Property::Array v2({1.0000001192092896f}); // 1.0f + FLT_EPSILON
+ * assert(v1 == v2); // true
+ * assert(v1.GetHash() == v2.GetHash()); // false, because of floating point precision issue.
+ * @endcode
+ *
+ * @SINCE_2_3.54
+ *
+ * @return Get the hashed value.
+ */
+ std::size_t GetHash() const;
+
/**
* @brief Output to stream.
* @SINCE_1_1.28
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// EXTERNAL INCLUDES
#include <dali/integration-api/debug.h>
+#include <limits>
// INTERNAL INCLUDES
+#include <dali/internal/common/hash-utils.h>
#include <dali/public-api/common/vector-wrapper.h>
namespace Dali
using IndexValuePair = std::pair<Property::Index, Property::Value>;
using IndexValueContainer = std::vector<IndexValuePair>;
+constexpr std::size_t NOT_HASHED = 0u;
+constexpr std::size_t ALWAYS_REHASH = std::numeric_limits<std::size_t>::max();
+
}; // unnamed namespace
struct Property::Map::Impl
{
+public:
+ std::size_t GetHash() const
+ {
+ std::size_t hash = mHash;
+ if(hash == ALWAYS_REHASH || hash == NOT_HASHED)
+ {
+ hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+
+ for(const auto& iter : mStringValueContainer)
+ {
+ // Use unordered hash operation.
+ auto valueHash = iter.second.GetHash();
+ hash += Dali::Internal::HashUtils::HashStringView(std::string_view(iter.first), valueHash);
+ }
+ for(const auto& iter : mIndexValueContainer)
+ {
+ // Use unordered hash operation.
+ auto valueHash = iter.second.GetHash();
+ hash += Dali::Internal::HashUtils::HashRawValue(iter.first, valueHash);
+ }
+
+ if(mHash != ALWAYS_REHASH)
+ {
+ mHash = hash;
+ }
+ }
+ return hash;
+ }
+
+public:
StringValueContainer mStringValueContainer;
IndexValueContainer mIndexValueContainer;
+
+ mutable std::size_t mHash{NOT_HASHED};
};
Property::Map::Map()
Property::Map::Map(const Property::Map& other)
: mImpl(new Impl)
{
- mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
- mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
+ if(DALI_LIKELY(other.mImpl))
+ {
+ mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
+ mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
+ // Keep mHash as NOT_HASHED.
+ }
}
Property::Map::Map(Property::Map&& other) noexcept
Property::Map::SizeType Property::Map::Count() const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- return mImpl->mStringValueContainer.size() + mImpl->mIndexValueContainer.size();
+ if(DALI_LIKELY(mImpl))
+ {
+ return mImpl->mStringValueContainer.size() + mImpl->mIndexValueContainer.size();
+ }
+ return 0;
}
bool Property::Map::Empty() const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
- return mImpl->mStringValueContainer.empty() && mImpl->mIndexValueContainer.empty();
+ if(DALI_LIKELY(mImpl))
+ {
+ return mImpl->mStringValueContainer.empty() && mImpl->mIndexValueContainer.empty();
+ }
+ return true;
}
void Property::Map::Insert(std::string key, Value value)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED)
+ {
+ // Use unordered hash operation.
+ auto valueHash = value.GetHash();
+ mImpl->mHash += Dali::Internal::HashUtils::HashStringView(std::string_view(key), valueHash);
+ }
mImpl->mStringValueContainer.push_back(std::make_pair(std::move(key), std::move(value)));
}
void Property::Map::Insert(Property::Index key, Value value)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED)
+ {
+ // Use unordered hash operation.
+ auto valueHash = value.GetHash();
+ mImpl->mHash += Dali::Internal::HashUtils::HashRawValue(key, valueHash);
+ }
mImpl->mIndexValueContainer.push_back(std::make_pair(key, std::move(value)));
}
Property::Value& Property::Map::GetValue(SizeType position) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
+
SizeType numStringKeys = mImpl->mStringValueContainer.size();
SizeType numIndexKeys = mImpl->mIndexValueContainer.size();
DALI_ASSERT_ALWAYS(position < (numStringKeys + numIndexKeys) && "position out-of-bounds");
{
DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetKey() is deprecated and will be removed from next release.\n");
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
+
SizeType numStringKeys = mImpl->mStringValueContainer.size();
DALI_ASSERT_ALWAYS(position < numStringKeys && "position out-of-bounds");
Property::Key Property::Map::GetKeyAt(SizeType position) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
SizeType numStringKeys = mImpl->mStringValueContainer.size();
SizeType numIndexKeys = mImpl->mIndexValueContainer.size();
{
DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetPair() is deprecated and will be removed from next release.\n");
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
SizeType numStringKeys = mImpl->mStringValueContainer.size();
KeyValuePair Property::Map::GetKeyValue(SizeType position) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
SizeType numStringKeys = mImpl->mStringValueContainer.size();
SizeType numIndexKeys = mImpl->mIndexValueContainer.size();
-
DALI_ASSERT_ALWAYS(position < (numStringKeys + numIndexKeys) && "position out-of-bounds");
if(position < numStringKeys)
Property::Value* Property::Map::Find(std::string_view key) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- for(auto&& iter : mImpl->mStringValueContainer)
+ if(DALI_LIKELY(mImpl))
{
- if(key == iter.first)
+ for(auto&& iter : mImpl->mStringValueContainer)
{
- return &iter.second;
+ if(key == iter.first)
+ {
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
+ return &iter.second;
+ }
}
}
return nullptr; // Not found
Property::Value* Property::Map::Find(Property::Index key) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- for(auto&& iter : mImpl->mIndexValueContainer)
+ if(DALI_LIKELY(mImpl))
{
- if(iter.first == key)
+ for(auto&& iter : mImpl->mIndexValueContainer)
{
- return &iter.second;
+ if(iter.first == key)
+ {
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
+ return &iter.second;
+ }
}
}
return nullptr; // Not found
Property::Value* Property::Map::Find(std::string_view key, Property::Type type) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- for(auto&& iter : mImpl->mStringValueContainer)
+ if(DALI_LIKELY(mImpl))
{
- if((iter.second.GetType() == type) && (key == iter.first))
+ for(auto&& iter : mImpl->mStringValueContainer)
{
- return &iter.second;
+ if((iter.second.GetType() == type) && (key == iter.first))
+ {
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
+ return &iter.second;
+ }
}
}
return nullptr; // Not found
Property::Value* Property::Map::Find(Property::Index key, Property::Type type) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- for(auto&& iter : mImpl->mIndexValueContainer)
+ if(DALI_LIKELY(mImpl))
{
- if((iter.second.GetType() == type) && (iter.first == key))
+ for(auto&& iter : mImpl->mIndexValueContainer)
{
- return &iter.second;
+ if((iter.second.GetType() == type) && (iter.first == key))
+ {
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
+ return &iter.second;
+ }
}
}
return nullptr; // Not found
void Property::Map::Clear()
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- mImpl->mStringValueContainer.clear();
- mImpl->mIndexValueContainer.clear();
+ if(DALI_LIKELY(mImpl))
+ {
+ mImpl->mStringValueContainer.clear();
+ mImpl->mIndexValueContainer.clear();
+ mImpl->mHash = NOT_HASHED;
+ }
}
bool Property::Map::Remove(Property::Index key)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- auto iter = std::find_if(mImpl->mIndexValueContainer.begin(), mImpl->mIndexValueContainer.end(), [key](const IndexValuePair& element) { return element.first == key; });
- if(iter != mImpl->mIndexValueContainer.end())
+ if(DALI_LIKELY(mImpl))
{
- mImpl->mIndexValueContainer.erase(iter);
- return true;
+ auto iter = std::find_if(mImpl->mIndexValueContainer.begin(), mImpl->mIndexValueContainer.end(), [key](const IndexValuePair& element) { return element.first == key; });
+ if(iter != mImpl->mIndexValueContainer.end())
+ {
+ if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED)
+ {
+ // Use unordered hash operation.
+ auto valueHash = iter->second.GetHash();
+ mImpl->mHash -= Dali::Internal::HashUtils::HashRawValue(key, valueHash);
+ }
+ mImpl->mIndexValueContainer.erase(iter);
+ return true;
+ }
}
return false;
}
bool Property::Map::Remove(std::string_view key)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
- auto iter = std::find_if(mImpl->mStringValueContainer.begin(), mImpl->mStringValueContainer.end(), [key](const StringValuePair& element) { return element.first == key; });
- if(iter != mImpl->mStringValueContainer.end())
+ if(DALI_LIKELY(mImpl))
{
- mImpl->mStringValueContainer.erase(iter);
- return true;
+ auto iter = std::find_if(mImpl->mStringValueContainer.begin(), mImpl->mStringValueContainer.end(), [key](const StringValuePair& element) { return element.first == key; });
+ if(iter != mImpl->mStringValueContainer.end())
+ {
+ if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED)
+ {
+ // Use unordered hash operation.
+ auto valueHash = iter->second.GetHash();
+ mImpl->mHash -= Dali::Internal::HashUtils::HashStringView(key, valueHash);
+ }
+ mImpl->mStringValueContainer.erase(iter);
+ return true;
+ }
}
return false;
}
void Property::Map::Merge(const Property::Map& from)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
// Ensure we're not attempting to merge with ourself
if(this != &from)
{
if(Count())
{
+ // Just reset hash as zero. (Since incremental merge is complex.)
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ mImpl->mHash = NOT_HASHED;
+ }
+
for(auto&& iter : from.mImpl->mStringValueContainer)
{
(*this)[iter.first] = iter.second;
const Property::Value& Property::Map::operator[](std::string_view key) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
for(auto&& iter : mImpl->mStringValueContainer)
{
Property::Value& Property::Map::operator[](std::string_view key)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
for(auto&& iter : mImpl->mStringValueContainer)
{
const Property::Value& Property::Map::operator[](Property::Index key) const
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ DALI_ASSERT_ALWAYS(mImpl && "Cannot use an object previously used as an r-value");
for(auto&& iter : mImpl->mIndexValueContainer)
{
Property::Value& Property::Map::operator[](Property::Index key)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+
+ if(mImpl->mHash != ALWAYS_REHASH)
+ {
+ // Mark as we cannot assume that hash is valid anymore.
+ // Recalculate hash always after now.
+ mImpl->mHash = ALWAYS_REHASH;
+ }
for(auto&& iter : mImpl->mIndexValueContainer)
{
Property::Map& Property::Map::operator=(const Property::Map& other)
{
- DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
-
if(this != &other)
{
- mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
- mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
+ if(DALI_UNLIKELY(other.mImpl == nullptr))
+ {
+ Clear();
+ }
+ else
+ {
+ if(DALI_UNLIKELY(!mImpl))
+ {
+ mImpl = new Impl();
+ }
+ mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
+ mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
+ mImpl->mHash = other.mImpl->mHash;
+ }
}
return *this;
}
return *this;
}
+bool Property::Map::operator==(const Property::Map& rhs) const
+{
+ // TODO : Need to check epsilon for float comparison in future. For now, just compare hash value and count.
+ return Count() == rhs.Count() && GetHash() == rhs.GetHash();
+}
+
+std::size_t Property::Map::GetHash() const
+{
+ return DALI_LIKELY(mImpl) ? mImpl->GetHash() : Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+}
+
std::ostream& operator<<(std::ostream& stream, const Property::Map& map)
{
stream << "Map(" << map.Count() << ") = {";
- if(map.mImpl)
+ if(DALI_LIKELY(map.mImpl))
{
int32_t count = 0;
// Output the String-Value pairs
}
stream << iter.first << ":" << iter.second;
}
+
+ if(map.mImpl->mHash != NOT_HASHED)
+ {
+ stream << "(hash=" << map.mImpl->mHash << ")";
+ }
}
stream << "}";
#define DALI_PROPERTY_MAP_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
Map& operator=(Map&& other) noexcept;
+ /**
+ * @brief Equality operator.
+ *
+ * @SINCE_2_3.54
+ * @param[in] rhs A reference for comparison
+ * @return True if equal type and equal value.
+ */
+ bool operator==(const Map& rhs) const;
+
+ /**
+ * @brief Inequality operator.
+ *
+ * @SINCE_2_3.54
+ * @param[in] rhs A reference for comparison
+ * @return True if not equal
+ */
+ bool operator!=(const Map& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ /**
+ * @brief Get hash value of the map.
+ *
+ * @note The order of key/value pairs is not considered.
+ * For example, Map({{"key", 1}, {"key2", 2}}) and Map({{"key2", 2}, {"key", 1}}) will have same hash value.
+ * But the type of Property::Value is considered.
+ * For example, Map({{"key", 1}}) and Map({{"key", 1.0f}}) might not have same hash value.
+ *
+ * @warning Hash might spend O(N) per each call.
+ * @warning Hash don't consider floating point precision. So even if two values equality return true,
+ * they can have different hash value.
+ * @code
+ * Property::Map v1({{1, 1.0f}});
+ * Property::Map v2({{1, 1.0000001192092896f}}); // 1.0f + FLT_EPSILON
+ * assert(v1 == v2); // true
+ * assert(v1.GetHash() == v2.GetHash()); // false, because of floating point precision issue.
+ * @endcode
+ *
+ * @SINCE_2_3.54
+ *
+ * @return Get the hashed value.
+ */
+ std::size_t GetHash() const;
+
/**
* @brief Output to stream.
* @SINCE_1_1.28
#include <dali/public-api/object/property-map.h>
#include <dali/public-api/object/property-types.h>
+#include <dali/internal/common/hash-utils.h>
+
/**
* As the Implementation is bit complex because of Small Buffer Optimization (SBO)
* In the Property::Value class and Tagged Union implementation in the Impl class.
Impl()
{
+ // DevNote - This feature should be keeped to be opitmized.
+ // See patch with name : Added small buffer optimization to Property::Value.
static_assert(sizeof(Impl) == 16);
static_assert(alignof(Impl) == alignof(Impl*));
Type GetType() const
{
- return mData.mType.type;
+ return mData.mMetadata.type;
}
bool GetBool() const
return mData.mExtents.member == other.mData.mExtents.member;
}
case Property::ARRAY:
+ {
+ return mData.mArray.member == other.mData.mArray.member;
+ }
case Property::MAP:
{
- // TODO : Need to support this case
- return false;
+ return mData.mMap.member == other.mData.mMap.member;
}
}
return false;
void SetType(Type typeValue)
{
- mData.mType.type = typeValue;
+ mData.mMetadata.type = typeValue;
+ mData.mMetadata.hash = 0u; ///< Reset hash value when changing type.
}
bool ConvertType(const Property::Type targetType)
{
bool converted = false;
- const Property::Type inputType = mData.mType.type;
+ const Property::Type inputType = mData.mMetadata.type;
if(inputType == targetType)
{
return converted;
}
+ std::size_t GetHash() const
+ {
+ std::size_t hash = mData.mMetadata.hash;
+ if(hash == 0u)
+ {
+ hash = Dali::Internal::HashUtils::INITIAL_HASH_VALUE;
+
+ switch(GetType())
+ {
+ case Property::NONE:
+ {
+ break;
+ }
+ case Property::BOOLEAN:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mBool.member, hash);
+ break;
+ }
+ case Property::FLOAT:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mFloat.member, hash);
+ break;
+ }
+ case Property::INTEGER:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mInt.member, hash);
+ break;
+ }
+ case Property::VECTOR2:
+ {
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mVector2.member.AsFloat(), 2, hash);
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mVector3.member.AsFloat(), 3, hash);
+ break;
+ }
+ case Property::VECTOR4:
+ {
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mVector4.member->AsFloat(), 4, hash);
+ break;
+ }
+ case Property::MATRIX3:
+ {
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mMatrix3.member->AsFloat(), 9, hash);
+ break;
+ }
+ case Property::MATRIX:
+ {
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mMatrix.member->AsFloat(), 16, hash);
+ break;
+ }
+ case Property::RECTANGLE:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mRect.member->x, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mRect.member->y, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mRect.member->width, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mRect.member->height, hash);
+ break;
+ }
+ case Property::ROTATION:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mAngleAxis.member->angle.radian, hash);
+ Dali::Internal::HashUtils::HashRawBuffer<float>(mData.mAngleAxis.member->axis.AsFloat(), 3, hash);
+ break;
+ }
+ case Property::STRING:
+ {
+ Dali::Internal::HashUtils::HashStringView(std::string_view(*mData.mString.member), hash);
+ break;
+ }
+ case Property::EXTENTS:
+ {
+ Dali::Internal::HashUtils::HashRawValue(mData.mExtents.member.start, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mExtents.member.end, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mExtents.member.top, hash);
+ Dali::Internal::HashUtils::HashRawValue(mData.mExtents.member.bottom, hash);
+ break;
+ }
+ case Property::ARRAY:
+ {
+ hash ^= mData.mArray.member.GetHash();
+ break;
+ }
+ case Property::MAP:
+ {
+ hash ^= mData.mMap.member.GetHash();
+ break;
+ }
+ }
+
+ // Don't store hash result for array and map type. (Since their value might be changed later)
+ if(!(mData.mMetadata.type == Property::ARRAY || mData.mMetadata.type == Property::MAP))
+ {
+ mData.mMetadata.hash = hash;
+ }
+ }
+
+ // For here, we can store only 24 bit hash value as maximum.
+ // So need to append the type info after hash calculate.
+ return ((static_cast<std::size_t>(mData.mMetadata.type) << 24) | (static_cast<std::size_t>(hash) & 0x00ffffff));
+ }
+
private:
/**
* This helper function takes a typed(Tp) memory location( member)
}
}
+ /**
+ * Data for property type and hash value.
+ */
+ struct Metadata
+ {
+ Type type : 8;
+ mutable uint32_t hash : 24;
+ }; // TODO : Tell the compiler it is okay to use a single 32 bit load. For example : __attribute__((packed, aligned(4))) for gcc
+
/*
* This wrapper struct is used for
* storing Type in every union member
template<typename T>
struct UnionMember
{
- Type type;
- T member;
+ Metadata metadata;
+ T member;
};
/**
UnionMember<AngleAxis*> mAngleAxis;
UnionMember<std::string*> mString;
UnionMember<Rect<int32_t>*> mRect;
- struct
- {
- Type type;
- } mType;
+
+ Metadata mMetadata;
};
Data mData;
return converted;
}
+std::size_t Property::Value::GetHash() const
+{
+ return Read().GetHash();
+}
+
std::ostream& operator<<(std::ostream& stream, const Property::Value& value)
{
const auto& obj = value.Read();
* @SINCE_2_1.31
* @param[in] rhs A reference for comparison
* @return True if equal type and equal value.
- * @note Property::ARRAY and Property::MAP don't support equality operator now. Always return false.
*/
bool operator==(const Value& rhs) const;
* @SINCE_2_1.31
* @param[in] rhs A reference for comparison
* @return True if not equal
- * @note Property::ARRAY and Property::MAP don't support equality operator now. Always return true.
*/
bool operator!=(const Value& rhs) const
{
*/
bool Get(Extents& extentsValue) const;
+ /**
+ * @brief Get hash value of the value.
+ *
+ * @warning Hash don't consider floating point precision. So even if two values equality return true,
+ * they can have different hash value.
+ * @code
+ * Property::Value v1(1.0f);
+ * Property::Value v2(1.0000001192092896f); // 1.0f + FLT_EPSILON
+ * assert(v1 == v2); // true
+ * assert(v1.GetHash() == v2.GetHash()); // false, because of floating point precision issue.
+ * @endcode
+ *
+ * @SINCE_2_3.54
+ *
+ * @return Get the hashed value.
+ */
+ std::size_t GetHash() const;
+
/**
* @brief Output to stream.
* @SINCE_1_0.0
#define DALI_PROPERTY_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* @brief Enumeration for the property types supported.
* @SINCE_1_0.0
*/
- enum Type
+ enum Type : uint8_t
{
NONE, ///< No type @SINCE_1_0.0