From bb0fda637ea49668bfe13474d038aaa6acf69a89 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Thu, 12 Dec 2024 20:35:54 +0900 Subject: [PATCH] Allow to use moved Property::Map & Property::Array Until now, we make those value's mImpl as nullptr. So their was a lots of DALI_ASSERT_DEBUG() to check whether they are moved or not. Those codes might not be fair than other moved objects implementation. we allow to use moved object like WeakHandle, or Dali::Vector. Let we also allow to use them. And let we make surely assert by DALI_ASSERT_ALWAYS if we need, instead DALI_ASSERT_DEBUG Change-Id: If08853a1635a8c33317edc1d25531223f7c427ed Signed-off-by: Eunki, Hong --- .../src/dali/utc-Dali-PropertyArray.cpp | 137 +++++++++-- .../src/dali/utc-Dali-PropertyMap.cpp | 182 +++++++++++--- .../src/dali/utc-Dali-PropertyValue.cpp | 4 +- dali/internal/common/hash-utils.h | 5 +- dali/public-api/object/property-array.cpp | 87 ++++--- dali/public-api/object/property-map.cpp | 231 +++++++++++------- 6 files changed, 462 insertions(+), 184 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-PropertyArray.cpp b/automated-tests/src/dali/utc-Dali-PropertyArray.cpp index 4cb671659..05a87b7f6 100644 --- a/automated-tests/src/dali/utc-Dali-PropertyArray.cpp +++ b/automated-tests/src/dali/utc-Dali-PropertyArray.cpp @@ -279,6 +279,21 @@ int UtcDaliPropertyArrayOstream02(void) 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; @@ -324,19 +339,10 @@ int UtcDaliPropertyArrayMoveConstructor(void) 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(array1)[0], exceptionMessage); - DALI_TEST_ASSERTION(Property::Array temp; array1 = temp, exceptionMessage); - END_TEST; } @@ -355,18 +361,10 @@ int UtcDaliPropertyArrayMoveAssignmentOperator(void) 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(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) @@ -383,6 +381,107 @@ int UtcDaliPropertyArrayMoveAssignmentOperator(void) 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(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(), 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(), TEST_LOCATION); + + array1 = array2; + + DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION); + DALI_TEST_EQUALS(2, array1[2].Get(), 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(), TEST_LOCATION); + + array1 = std::move(array2); + + DALI_TEST_EQUALS(3u, array1.Size(), TEST_LOCATION); + DALI_TEST_EQUALS(2, array1[2].Get(), 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"}; diff --git a/automated-tests/src/dali/utc-Dali-PropertyMap.cpp b/automated-tests/src/dali/utc-Dali-PropertyMap.cpp index 22f2e7769..11f179f7b 100644 --- a/automated-tests/src/dali/utc-Dali-PropertyMap.cpp +++ b/automated-tests/src/dali/utc-Dali-PropertyMap.cpp @@ -92,31 +92,15 @@ int UtcDaliPropertyMapMoveConstructor(void) 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(map1)["key"], exceptionMessage); - DALI_TEST_ASSERTION(map1[0], exceptionMessage); DALI_TEST_ASSERTION(const_cast(map1)[0], exceptionMessage); - DALI_TEST_ASSERTION(Property::Map temp; map1 = temp, exceptionMessage); END_TEST; } @@ -136,31 +120,15 @@ int UtcDaliPropertyMapMoveAssignmentOperator(void) 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(map1)["key"], exceptionMessage); - DALI_TEST_ASSERTION(map1[0], exceptionMessage); DALI_TEST_ASSERTION(const_cast(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) @@ -177,6 +145,137 @@ int UtcDaliPropertyMapMoveAssignmentOperator(void) 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(map1)["key"], exceptionMessage); + DALI_TEST_ASSERTION(const_cast(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(), TEST_LOCATION); + DALI_TEST_EQUALS(1, map1.Find("hello")->Get(), 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(), TEST_LOCATION); + DALI_TEST_EQUALS(1, map1.Find("hello")->Get(), 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(), TEST_LOCATION); + DALI_TEST_EQUALS(1, map1.Find("hello")->Get(), 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(), TEST_LOCATION); + DALI_TEST_EQUALS(1, map1.Find("hello")->Get(), 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; @@ -724,6 +823,21 @@ int UtcDaliPropertyMapOstream02(void) 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"); diff --git a/automated-tests/src/dali/utc-Dali-PropertyValue.cpp b/automated-tests/src/dali/utc-Dali-PropertyValue.cpp index f49c9b49d..32817b5a6 100644 --- a/automated-tests/src/dali/utc-Dali-PropertyValue.cpp +++ b/automated-tests/src/dali/utc-Dali-PropertyValue.cpp @@ -560,7 +560,7 @@ int UtcDaliPropertyValueMoveConstructorArray(void) 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); @@ -578,7 +578,7 @@ int UtcDaliPropertyValueMoveConstructorMap(void) 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); diff --git a/dali/internal/common/hash-utils.h b/dali/internal/common/hash-utils.h index da66690ee..81639ec4c 100644 --- a/dali/internal/common/hash-utils.h +++ b/dali/internal/common/hash-utils.h @@ -29,10 +29,7 @@ namespace Dali::Internal::HashUtils { -enum -{ - INITIAL_HASH_VALUE = 5381 -}; +constexpr std::size_t INITIAL_HASH_VALUE = 5381; /* * djb2 (http://www.cse.yorku.ca/~oz/hash.html) diff --git a/dali/public-api/object/property-array.cpp b/dali/public-api/object/property-array.cpp index 17f4a802b..640500f4f 100644 --- a/dali/public-api/object/property-array.cpp +++ b/dali/public-api/object/property-array.cpp @@ -82,7 +82,11 @@ Property::Array::Array(const std::initializer_list& values) 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 @@ -98,13 +102,16 @@ Property::Array::~Array() 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. @@ -115,20 +122,30 @@ void Property::Array::PushBack(const Value& value) void Property::Array::Clear() { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - mImpl->mArray.clear(); - mImpl->mHash = NOT_HASHED; + 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"); + if(DALI_UNLIKELY(!mImpl)) + { + mImpl = new Impl(); + } + if(mImpl->mArray.size() != size) { mImpl->mArray.resize(size); @@ -143,13 +160,12 @@ void Property::Array::Resize(SizeType size) 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]; @@ -157,7 +173,7 @@ const Property::Value& Property::Array::operator[](SizeType index) const 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) @@ -171,12 +187,21 @@ Property::Value& Property::Array::operator[](SizeType 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; - mImpl->mHash = other.mImpl->mHash; + 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; } @@ -194,35 +219,37 @@ Property::Array& Property::Array::operator=(Property::Array&& other) noexcept bool Property::Array::operator==(const Property::Array& rhs) const { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - // 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 { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - return mImpl->GetHash(); + 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 << "]"; - if(array.mImpl->mHash != NOT_HASHED) - { - stream << "(hash=" << array.mImpl->mHash << ")"; - } + stream << "]"; return stream; } diff --git a/dali/public-api/object/property-map.cpp b/dali/public-api/object/property-map.cpp index e7a5f8ffe..ebbf2a0c6 100644 --- a/dali/public-api/object/property-map.cpp +++ b/dali/public-api/object/property-map.cpp @@ -108,8 +108,12 @@ Property::Map::Map(const std::initializer_list& values) 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 @@ -125,19 +129,29 @@ Property::Map::~Map() 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. @@ -149,7 +163,11 @@ void Property::Map::Insert(std::string key, Value 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. @@ -161,7 +179,8 @@ void Property::Map::Insert(Property::Index key, Value 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"); @@ -180,7 +199,8 @@ const std::string& Property::Map::GetKey(SizeType position) const { 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"); @@ -189,7 +209,7 @@ const std::string& Property::Map::GetKey(SizeType position) const 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(); @@ -211,7 +231,7 @@ StringValuePair& Property::Map::GetPair(SizeType position) const { 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(); @@ -222,11 +242,10 @@ StringValuePair& Property::Map::GetPair(SizeType position) const 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) @@ -243,19 +262,20 @@ KeyValuePair Property::Map::GetKeyValue(SizeType position) const 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) { - if(mImpl->mHash != ALWAYS_REHASH) + if(key == iter.first) { - // Mark as we cannot assume that hash is valid anymore. - // Recalculate hash always after now. - mImpl->mHash = ALWAYS_REHASH; + 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 &iter.second; } } return nullptr; // Not found @@ -263,19 +283,20 @@ Property::Value* Property::Map::Find(std::string_view key) const 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) { - if(mImpl->mHash != ALWAYS_REHASH) + if(iter.first == key) { - // Mark as we cannot assume that hash is valid anymore. - // Recalculate hash always after now. - mImpl->mHash = ALWAYS_REHASH; + 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 &iter.second; } } return nullptr; // Not found @@ -293,19 +314,20 @@ Property::Value* Property::Map::Find(Property::Index indexKey, std::string_view 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) { - if(mImpl->mHash != ALWAYS_REHASH) + if((iter.second.GetType() == type) && (key == iter.first)) { - // Mark as we cannot assume that hash is valid anymore. - // Recalculate hash always after now. - mImpl->mHash = ALWAYS_REHASH; + 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 &iter.second; } } return nullptr; // Not found @@ -313,19 +335,20 @@ Property::Value* Property::Map::Find(std::string_view key, Property::Type type) 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) { - if(mImpl->mHash != ALWAYS_REHASH) + if((iter.second.GetType() == type) && (iter.first == key)) { - // Mark as we cannot assume that hash is valid anymore. - // Recalculate hash always after now. - mImpl->mHash = ALWAYS_REHASH; + 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 &iter.second; } } return nullptr; // Not found @@ -333,54 +356,60 @@ Property::Value* Property::Map::Find(Property::Index key, Property::Type type) c void Property::Map::Clear() { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - - mImpl->mStringValueContainer.clear(); - mImpl->mIndexValueContainer.clear(); - mImpl->mHash = NOT_HASHED; + 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)) { - if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED) + auto iter = std::find_if(mImpl->mIndexValueContainer.begin(), mImpl->mIndexValueContainer.end(), [key](const IndexValuePair& element) { return element.first == key; }); + if(iter != mImpl->mIndexValueContainer.end()) { - // Use unordered hash operation. - auto valueHash = iter->second.GetHash(); - mImpl->mHash -= Dali::Internal::HashUtils::HashRawValue(key, valueHash); + 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; } - 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)) { - if(mImpl->mHash != ALWAYS_REHASH && mImpl->mHash != NOT_HASHED) + auto iter = std::find_if(mImpl->mStringValueContainer.begin(), mImpl->mStringValueContainer.end(), [key](const StringValuePair& element) { return element.first == key; }); + if(iter != mImpl->mStringValueContainer.end()) { - // Use unordered hash operation. - auto valueHash = iter->second.GetHash(); - mImpl->mHash -= Dali::Internal::HashUtils::HashStringView(key, valueHash); + 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; } - 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) @@ -413,7 +442,7 @@ void Property::Map::Merge(const Property::Map& from) 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) { @@ -428,7 +457,10 @@ const Property::Value& Property::Map::operator[](std::string_view key) const 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) { @@ -452,7 +484,7 @@ Property::Value& Property::Map::operator[](std::string_view key) 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) { @@ -467,7 +499,10 @@ const Property::Value& Property::Map::operator[](Property::Index key) const 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) { @@ -491,13 +526,22 @@ Property::Value& Property::Map::operator[](Property::Index key) 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; - mImpl->mHash = other.mImpl->mHash; + 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; } @@ -515,23 +559,20 @@ Property::Map& Property::Map::operator=(Property::Map&& other) noexcept bool Property::Map::operator==(const Property::Map& rhs) const { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - // 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 { - DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value"); - return mImpl->GetHash(); + 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 @@ -553,15 +594,15 @@ std::ostream& operator<<(std::ostream& stream, const Property::Map& map) } stream << iter.first << ":" << iter.second; } + + if(map.mImpl->mHash != NOT_HASHED) + { + stream << "(hash=" << map.mImpl->mHash << ")"; + } } stream << "}"; - if(map.mImpl->mHash != NOT_HASHED) - { - stream << "(hash=" << map.mImpl->mHash << ")"; - } - return stream; } -- 2.34.1