From: Eunki, Hong Date: Tue, 14 Jan 2025 12:33:59 +0000 (+0900) Subject: Support equality operator for Property::Map and Property::Array X-Git-Tag: dali_2.4.2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0fa5ad05007f743f6410cbedd2c887cb43f0acfb;p=platform%2Fcore%2Fuifw%2Fdali-core.git Support equality operator for Property::Map and Property::Array Change-Id: I8528b5cc46be1cd7c1ba2d6c44c0a39018997917 Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali/utc-Dali-PropertyArray.cpp b/automated-tests/src/dali/utc-Dali-PropertyArray.cpp index 05a87b7f6..92c6595d3 100644 --- a/automated-tests/src/dali/utc-Dali-PropertyArray.cpp +++ b/automated-tests/src/dali/utc-Dali-PropertyArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -403,6 +403,10 @@ int UtcDaliPropertyArrayMovedArrayP1(void) DALI_TEST_EQUALS(0u, array1.Count(), TEST_LOCATION); DALI_TEST_EQUALS(0u, array1.Capacity(), TEST_LOCATION); DALI_TEST_EQUALS(true, array1.Empty(), TEST_LOCATION); + + // DALI_TEST_EQUALS copy the array. We should use DALI_TEST_CHECK + DALI_TEST_CHECK(emptyArray == array1); + DALI_TEST_CHECK(array1 == emptyArray); array1.Clear(); // Test reserve @@ -654,8 +658,8 @@ int UtcDaliPropertyArrayEqualNonFloatType(void) array2.PushBack(1); array2.PushBack(false); - array2.PushBack(subArray1); - array2.PushBack(subMap1); + array2.PushBack(subArray2); + array2.PushBack(subMap2); array2.PushBack(4); DALI_TEST_CHECK(array1 == array2); @@ -685,3 +689,71 @@ int UtcDaliPropertyArrayEqualNonFloatType(void) END_TEST; } + +int UtcDaliPropertyArrayEqualFloatType(void) +{ + tet_infoline("Check Property::Array equality even if some values need to consider epsilon"); + + Property::Array array1; + Property::Array subArray1; + Property::Map subMap1; + + subArray1.PushBack(2.0f); + subArray1.PushBack(3); + + subMap1.Insert(0, "0"); + subMap1.Insert("1", 1.0f); + + array1.PushBack(1.0f); + 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.0f + Math::MACHINE_EPSILON_1); + subArray2.PushBack(3); + + subMap2.Insert(0, "0"); + subMap2.Insert("1", 1.0f - Math::MACHINE_EPSILON_1); + + array2.PushBack(1.0f + Math::MACHINE_EPSILON_1); + DALI_TEST_CHECK(array1 != array2); + + array2.PushBack(false); + DALI_TEST_CHECK(array1 != array2); + + array2.PushBack(subArray2); + DALI_TEST_CHECK(array1 != array2); + + array2.PushBack(subMap2); + DALI_TEST_CHECK(array1 != array2); + + array2.PushBack(4); + + DALI_TEST_CHECK(array1 == array2); + DALI_TEST_EQUALS(array1, array2, TEST_LOCATION); + + // Hash value may not be equal! + DALI_TEST_NOT_EQUALS(array1.GetHash(), array2.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION); + + array2.PushBack(5); + + DALI_TEST_CHECK(array1 != array2); + + array2.Resize(5); + + DALI_TEST_CHECK(array1 == array2); + DALI_TEST_EQUALS(array1, array2, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-PropertyMap.cpp b/automated-tests/src/dali/utc-Dali-PropertyMap.cpp index 11f179f7b..a42528d1f 100644 --- a/automated-tests/src/dali/utc-Dali-PropertyMap.cpp +++ b/automated-tests/src/dali/utc-Dali-PropertyMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -175,6 +175,10 @@ int UtcDaliPropertyMapMovedMapP1(void) 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); + + // DALI_TEST_EQUALS copy the map. We should use DALI_TEST_CHECK + DALI_TEST_CHECK(emptyMap == map1); + DALI_TEST_CHECK(map1 == emptyMap); map1.Clear(); DALI_TEST_EQUALS(false, map1.Remove(10), TEST_LOCATION); @@ -1135,11 +1139,11 @@ int UtcDaliPropertyMapEqualNonFloatType(void) subMap2.Insert("1", 1); subMap2.Insert(0, "0"); - map2.Insert(3, subArray1); + map2.Insert(3, subArray2); map2.Insert(2, false); map2.Insert(1, 1); map2.Insert("5", 4); - map2.Insert("4", subMap1); + map2.Insert("4", subMap2); DALI_TEST_CHECK(map1 == map2); DALI_TEST_EQUALS(map1, map2, TEST_LOCATION); @@ -1167,3 +1171,74 @@ int UtcDaliPropertyMapEqualNonFloatType(void) END_TEST; } + +int UtcDaliPropertyMapEqualFloatType(void) +{ + tet_infoline("Check Property::Map equality even if some values need to consider epsilon"); + + Property::Map map1; + Property::Array subArray1; + Property::Map subMap1; + + subArray1.PushBack(2.0f); + subArray1.PushBack(3); + + subMap1.Insert(0, "0"); + subMap1.Insert("1", 1.0f); + + map1.Insert(1, 1.0f); + 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.0f + Math::MACHINE_EPSILON_1); + subArray2.PushBack(3); + + subMap2.Insert("1", 1.0f - Math::MACHINE_EPSILON_1); + subMap2.Insert(0, "0"); + + map2.Insert(3, subArray2); + DALI_TEST_CHECK(map1 != map2); + + map2.Insert(2, false); + DALI_TEST_CHECK(map1 != map2); + + map2.Insert(1, 1.0f + Math::MACHINE_EPSILON_1); + DALI_TEST_CHECK(map1 != map2); + + map2.Insert("5", 4); + DALI_TEST_CHECK(map1 != map2); + + map2.Insert("4", subMap2); + + DALI_TEST_CHECK(map1 == map2); + DALI_TEST_EQUALS(map1, map2, TEST_LOCATION); + + // Hash value may not be equal! + DALI_TEST_NOT_EQUALS(map1.GetHash(), map2.GetHash(), Math::MACHINE_EPSILON_100, TEST_LOCATION); + + map2.Insert("6", 8); + DALI_TEST_CHECK(map1 != map2); + + map2.Remove(2); + DALI_TEST_CHECK(map1 != map2); + + map2.Insert(2, false); + DALI_TEST_CHECK(map1 != map2); + + map2.Remove("6"); + DALI_TEST_CHECK(map1 == map2); + + END_TEST; +} diff --git a/dali/public-api/object/property-array.cpp b/dali/public-api/object/property-array.cpp index 640500f4f..14953061c 100644 --- a/dali/public-api/object/property-array.cpp +++ b/dali/public-api/object/property-array.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -219,8 +219,34 @@ Property::Array& Property::Array::operator=(Property::Array&& other) noexcept 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(); + if(DALI_UNLIKELY(this == &rhs)) + { + // Fast out for self comparision + return true; + } + + const auto lhsCount = Count(); + if(lhsCount != rhs.Count()) + { + return false; + } + if(DALI_UNLIKELY(mImpl == nullptr)) + { + return rhs.Empty(); + } + if(DALI_UNLIKELY(rhs.mImpl == nullptr)) + { + return Empty(); + } + + for(SizeType i = 0u; i < lhsCount; ++i) + { + if(mImpl->mArray[i] != rhs.mImpl->mArray[i]) + { + return false; + } + } + return true; } std::size_t Property::Array::GetHash() const diff --git a/dali/public-api/object/property-map.cpp b/dali/public-api/object/property-map.cpp index ebbf2a0c6..4f078c742 100644 --- a/dali/public-api/object/property-map.cpp +++ b/dali/public-api/object/property-map.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -21,6 +21,7 @@ // EXTERNAL INCLUDES #include #include +#include // INTERNAL INCLUDES #include @@ -559,8 +560,76 @@ Property::Map& Property::Map::operator=(Property::Map&& other) noexcept 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(); + if(DALI_UNLIKELY(this == &rhs)) + { + // Fast out for self comparision + return true; + } + + if(Count() != rhs.Count()) + { + return false; + } + if(DALI_UNLIKELY(mImpl == nullptr)) + { + return rhs.Empty(); + } + if(DALI_UNLIKELY(rhs.mImpl == nullptr)) + { + return Empty(); + } + + // TODO : Should we support duplication key comparision? + { + std::unordered_map stringValueMap; + for(auto&& iter : mImpl->mStringValueContainer) + { + stringValueMap[std::string_view(iter.first)] = &iter.second; + } + for(auto&& iter : rhs.mImpl->mStringValueContainer) + { + auto mapIter = stringValueMap.find(std::string_view(iter.first)); + if(mapIter == stringValueMap.end()) + { + return false; + } + if(*(mapIter->second) != iter.second) + { + return false; + } + stringValueMap.erase(mapIter); + } + if(!stringValueMap.empty()) + { + return false; + } + } + { + std::unordered_map indexValueMap; + for(auto&& iter : mImpl->mIndexValueContainer) + { + indexValueMap[iter.first] = &iter.second; + } + for(auto&& iter : rhs.mImpl->mIndexValueContainer) + { + auto mapIter = indexValueMap.find(iter.first); + if(mapIter == indexValueMap.end()) + { + return false; + } + if(*(mapIter->second) != iter.second) + { + return false; + } + indexValueMap.erase(mapIter); + } + if(!indexValueMap.empty()) + { + return false; + } + } + + return true; } std::size_t Property::Map::GetHash() const