From 33a8477946185463936981476e9772d40c37fd72 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Thu, 3 Feb 2022 16:20:06 +0900 Subject: [PATCH] Add Internal::IndexedMap Make IndexedMap that key can be std::uint32_t and Internal::ConstString IndexedMap can only do Register + Get. We can check unique registration by this API. IndexedMap use iterator as std::vector>::iterator. Get API return iterator that key contained. If found failed, return End() iterator. Internally, we make it sorted key-index-element container. It can search key by binary search. and less element copy action. (ConstString can be convert const char* == size_t which can comparable) Time complexity is O(|Element count|) for Register and O(log|Element count|) for Get Change some std::vector container as IndexedConstStringMap and IndexedIntegerMap at type-info and type-register. type-info is very important area of DALi engine. So I append some define blocks when we meet some strange problems in future. It will be remove when this patch is safe enough. Change-Id: I7ad2e1a4776a4acedb4632053419b4fdcfa043bb Signed-off-by: Eunki, Hong --- automated-tests/src/dali-internal/CMakeLists.txt | 4 +- .../utc-Dali-Internal-IndexedConstStringMap.cpp | 419 +++++++++++++++++++++ .../utc-Dali-Internal-IndexedIntegerMap.cpp | 374 ++++++++++++++++++ dali/internal/common/indexed-const-string-map.h | 182 +++++++++ dali/internal/common/indexed-integer-map.h | 169 +++++++++ dali/internal/common/indexed-map-base.h | 398 +++++++++++++++++++ dali/internal/event/common/type-info-impl.cpp | 147 +++++++- dali/internal/event/common/type-info-impl.h | 30 +- dali/internal/event/common/type-registry-impl.cpp | 124 +++--- dali/internal/event/common/type-registry-impl.h | 5 +- 10 files changed, 1746 insertions(+), 106 deletions(-) create mode 100644 automated-tests/src/dali-internal/utc-Dali-Internal-IndexedConstStringMap.cpp create mode 100644 automated-tests/src/dali-internal/utc-Dali-Internal-IndexedIntegerMap.cpp create mode 100644 dali/internal/common/indexed-const-string-map.h create mode 100644 dali/internal/common/indexed-integer-map.h create mode 100644 dali/internal/common/indexed-map-base.h diff --git a/automated-tests/src/dali-internal/CMakeLists.txt b/automated-tests/src/dali-internal/CMakeLists.txt index 64a73b5..c1a3fcb 100644 --- a/automated-tests/src/dali-internal/CMakeLists.txt +++ b/automated-tests/src/dali-internal/CMakeLists.txt @@ -8,11 +8,14 @@ SET(CAPI_LIB "dali-internal") SET(TC_SOURCES utc-Dali-Internal-ActorObserver.cpp utc-Dali-Internal-ActorRelayout.cpp + utc-Dali-Internal-ConstString.cpp utc-Dali-Internal-Core.cpp utc-Dali-Internal-FixedSizeMemoryPool.cpp utc-Dali-Internal-FrustumCulling.cpp utc-Dali-Internal-Gesture.cpp utc-Dali-Internal-Handles.cpp + utc-Dali-Internal-IndexedConstStringMap.cpp + utc-Dali-Internal-IndexedIntegerMap.cpp utc-Dali-Internal-LongPressGesture.cpp utc-Dali-Internal-MemoryPoolObjectAllocator.cpp utc-Dali-Internal-OwnerPointer.cpp @@ -22,7 +25,6 @@ SET(TC_SOURCES utc-Dali-Internal-RotationGesture.cpp utc-Dali-Internal-TapGesture.cpp utc-Dali-Internal-TapGestureProcessor.cpp - utc-Dali-Internal-ConstString.cpp utc-Dali-Internal-TransformManagerProperty.cpp ) diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedConstStringMap.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedConstStringMap.cpp new file mode 100644 index 0000000..1ee223d --- /dev/null +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedConstStringMap.cpp @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2022 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. + * + */ + +#include +#include + +#include +#include + +// Internal headers are allowed here +#include + +using namespace Dali; +using Dali::Internal::ConstString; +using Dali::Internal::IndexedConstStringMap; +namespace +{ +std::string RandomString(size_t length) +{ + static auto& chrs = + "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + thread_local static std::mt19937 rg{std::random_device{}()}; + thread_local static std::uniform_int_distribution pick(0, sizeof(chrs) - 2); + + std::string s; + + s.reserve(length); + + while(length--) + s += chrs[pick(rg)]; + + return s; +} + +// Custom << operator to print debugging log. +std::basic_ostream& operator<<(std::basic_ostream& os, const ConstString& constString) +{ + std::string convertedString = std::string(constString.GetStringView()); + os << convertedString; + return os; +} + +} // namespace + +void utc_dali_internal_indexed_conststring_map_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_internal_indexed_conststring_map_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int UtcDaliIndexedConstStringMapEmpty(void) +{ + IndexedConstStringMap indexedMap; + DALI_TEST_EQUALS(indexedMap.Empty(), true, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.empty(), true, TEST_LOCATION); + + ConstString str("hello"); + int value = 3; + DALI_TEST_EQUALS(indexedMap.Register(str, value), true, TEST_LOCATION); + + DALI_TEST_EQUALS(indexedMap.Empty(), false, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.empty(), false, TEST_LOCATION); + + DALI_TEST_EQUALS(indexedMap.Count(), 1, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.size(), 1, TEST_LOCATION); + + DALI_TEST_EQUALS(indexedMap.Get(str)->first, str, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.Get(str)->second, value, TEST_LOCATION); + + indexedMap.Clear(); + DALI_TEST_EQUALS(indexedMap.Empty(), true, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.empty(), true, TEST_LOCATION); + + DALI_TEST_CHECK(indexedMap.Get(str) == indexedMap.End()); + + END_TEST; +} + +int UtcDaliIndexedConstStringMap(void) +{ + IndexedConstStringMap indexedMap; + + auto IndexedMapGetValueTest = [](const IndexedConstStringMap& indexedMap, ConstString key, bool registered, int element, const char* location) { + const auto& iter = indexedMap.Get(key); + DALI_TEST_EQUALS(!(iter == indexedMap.end()), registered, location); + if(registered) + { + DALI_TEST_EQUALS(iter->second, element, location); + } + }; + + ConstString keyFirst = ConstString("first"); + ConstString keySecond = ConstString("second"); + ConstString keyThird = ConstString("third"); + ConstString keyFourth = ConstString("fourth"); + + // Check. empty state + DALI_TEST_EQUALS(0u, indexedMap.Count(), TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.Begin() == indexedMap.End()); + DALI_TEST_CHECK(indexedMap.Empty()); + DALI_TEST_EQUALS(0u, indexedMap.size(), TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.begin() == indexedMap.end()); + DALI_TEST_CHECK(indexedMap.empty()); + + // phase 1 - Regist two element + DALI_TEST_CHECK(indexedMap.Register(keyFirst, 1)); + DALI_TEST_CHECK(indexedMap.Register(keySecond, 2)); + + // Get data by key + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + DALI_TEST_CHECK(!indexedMap.Empty()); + IndexedMapGetValueTest(indexedMap, ConstString("first"), true, 1, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, ConstString("second"), true, 2, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, ConstString("third"), false, 0, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, ConstString("fourth"), false, 0, TEST_LOCATION); + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 1, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 2, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 1, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 2, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedConstStringMap::KeyElementPairType(keyFirst, 1)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap::KeyElementPairType(keySecond, 2)); + + // Const iteration check + for(const auto& elem : indexedMap) + { + if(elem.first == keyFirst) + { + DALI_TEST_EQUALS(elem.second, 1, TEST_LOCATION); + } + else if(elem.first == keySecond) + { + DALI_TEST_EQUALS(elem.second, 2, TEST_LOCATION); + } + else + { + DALI_TEST_CHECK(false); // Should not get here + } + } + + // Iteration and fix data check + for(auto&& elem : indexedMap) + { + if(elem.first == keyFirst) + { + elem.second += 110; + } + } + // operator[] fix data check + indexedMap[keySecond] += 220; + + // Get data by key + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, true, 111, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, true, 222, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, false, 0, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, false, 0, TEST_LOCATION); + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedConstStringMap::KeyElementPairType(keyFirst, 111)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap::KeyElementPairType(keySecond, 222)); + + // Const iteration check + for(const auto& elem : indexedMap) + { + if(elem.first == keyFirst) + { + DALI_TEST_EQUALS(elem.second, 111, TEST_LOCATION); + } + else if(elem.first == keySecond) + { + DALI_TEST_EQUALS(elem.second, 222, TEST_LOCATION); + } + else + { + DALI_TEST_CHECK(false); // Should not get here + } + } + + // phase 2 - Regist two more element + DALI_TEST_CHECK(!indexedMap.Register(keyFirst, 11)); // Register failed when we try to insert data with same key + DALI_TEST_CHECK(!indexedMap.Register(keySecond, 22)); // Register failed when we try to insert data with same key + DALI_TEST_CHECK(indexedMap.Register(keyThird, 3)); + DALI_TEST_CHECK(indexedMap.Register(keyFourth, 4)); + + // Get data by key + DALI_TEST_EQUALS(4, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, true, 111, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, true, 222, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, true, 3, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, true, 4, TEST_LOCATION); + + // Get elemnt as l-value + { + auto iter = indexedMap.Get(keyFourth); + DALI_TEST_CHECK(iter != indexedMap.end()) + { + iter->second = 444; + } + } + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keyThird], 3, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keyFourth], 444, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(2), 3, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(3), 444, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(2), keyThird, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(3), keyFourth, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedConstStringMap::KeyElementPairType(keyFirst, 111)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap::KeyElementPairType(keySecond, 222)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(2) == IndexedConstStringMap::KeyElementPairType(keyThird, 3)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(3) == IndexedConstStringMap::KeyElementPairType(keyFourth, 444)); + + // For coverage + DALI_TEST_EQUALS(const_cast&>(indexedMap)[keyFirst], 111, TEST_LOCATION); + + // Clear check + DALI_TEST_CHECK(!indexedMap.Empty()); + indexedMap.Clear(); + DALI_TEST_CHECK(indexedMap.Empty()); + DALI_TEST_EQUALS(0u, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, false, 1, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, false, 2, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, false, 3, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, false, 4, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliIndexedConstStringMapNegative(void) +{ + tet_infoline("Negative test when IndexedConstStringMap access non-exist elements."); + + IndexedConstStringMap indexedMap; + + auto IndexedMapAssertTestWithIndex = [](IndexedConstStringMap& indexedMap, int testIndex) { + tet_printf("operator[] test"); + // Assert when try to access as const operator[] input with not registered key. + try + { + const auto& elem = const_cast&>(indexedMap)[ConstString("333")]; + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + // Assert when try to access as operator[] input with not registered key. + try + { + indexedMap[ConstString("333")] = 0; + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetElementByIndex test"); + // Assert when try to access as GetElementByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetElementByIndex(testIndex); + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetKeyByIndex test"); + // Assert when try to access as GetKeyByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetKeyByIndex(testIndex); + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetKeyElementPairByIndex test"); + // Assert when try to access as GetKeyByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetKeyElementPairByIndex(testIndex); + if(elem == IndexedConstStringMap::KeyElementPairType(ConstString("zero"), 0)) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + }; + // Assert test with empty indexedMap. + DALI_TEST_CHECK(indexedMap.Empty()); + IndexedMapAssertTestWithIndex(indexedMap, 0); + + // Register 2 data + DALI_TEST_CHECK(indexedMap.Register(ConstString("first"), 1)); + DALI_TEST_CHECK(indexedMap.Register(ConstString("second"), 2)); + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + IndexedMapAssertTestWithIndex(indexedMap, 2); + + // Test with always-invalid index like -1 + IndexedMapAssertTestWithIndex(indexedMap, -1); + + END_TEST; +} + +int UtcDaliIndexedConstStringMapStressTest(void) +{ + // Copy from utc-Dali-Internal-ConstString.cpp + static constexpr size_t DB_SIZE = 2000; + + std::vector Database; + Database.reserve(DB_SIZE); + + IndexedConstStringMap constStringDB1; + constStringDB1.reserve(DB_SIZE); + + IndexedConstStringMap constStringDB2; + constStringDB2.reserve(DB_SIZE); + + for(auto i = 0u; i < DB_SIZE; i++) + { + if(i % 3 == 0) + { + Database.push_back(RandomString(10)); + } + else if(i % 4 == 0) + { + Database.push_back(RandomString(7)); + } + else + { + Database.push_back(RandomString(11)); + } + std::string randomValue = RandomString(10); + DALI_TEST_EQUALS(constStringDB1.Register(ConstString(Database[i]), ConstString(randomValue)), true, TEST_LOCATION); + DALI_TEST_EQUALS(constStringDB2.Register(ConstString(Database[i]), randomValue), true, TEST_LOCATION); + } + + // Try to extra regist with same key + for(auto i = 0u; i < DB_SIZE; i++) + { + std::string randomValue = RandomString(2); + DALI_TEST_EQUALS(constStringDB1.Register(ConstString(Database[i]), ConstString(randomValue)), false, TEST_LOCATION); + DALI_TEST_EQUALS(constStringDB2.Register(ConstString(Database[i]), randomValue), false, TEST_LOCATION); + } + + // check eqality betwwen original string and constString + for(auto i = 0u; i < DB_SIZE; i++) + { + DALI_TEST_EQUALS(constStringDB1.GetKeyByIndex(i).GetCString(), Database[i].c_str(), TEST_LOCATION); + DALI_TEST_EQUALS(constStringDB2.GetKeyByIndex(i).GetCString(), Database[i].c_str(), TEST_LOCATION); + } + + // check pointer eqality betwwen 2 constString + for(auto i = 0u; i < DB_SIZE; i++) + { + bool pointerEqual = (constStringDB1[ConstString(Database[i])] == ConstString(constStringDB2[ConstString(Database[i])])); + DALI_TEST_EQUALS(pointerEqual, true, TEST_LOCATION); + } + + END_TEST; +} diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedIntegerMap.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedIntegerMap.cpp new file mode 100644 index 0000000..a93748f --- /dev/null +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-IndexedIntegerMap.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2022 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. + * + */ + +#include + +#include +#include + +#include + +using namespace Dali; +using Dali::Internal::IndexedIntegerMap; + +void utc_dali_indexed_integer_map_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_indexed_integer_map_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int UtcDaliIndexedIntegerMap(void) +{ + IndexedIntegerMap indexedMap; + const std::uint32_t keyFirst = 111111u; + const std::uint32_t keySecond = 222222u; + const std::uint32_t keyThird = 333333u; + const std::uint32_t keyFourth = 444444u; + + auto IndexedMapGetValueTest = [](const IndexedIntegerMap& indexedMap, std::uint32_t key, bool registered, int element, const char* location) { + const auto& iter = indexedMap.Get(key); + DALI_TEST_EQUALS(!(iter == indexedMap.end()), registered, location); + if(registered) + { + DALI_TEST_EQUALS(iter->second, element, location); + } + }; + + // Check. empty state + DALI_TEST_EQUALS(0u, indexedMap.Count(), TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.Begin() == indexedMap.End()); + DALI_TEST_CHECK(indexedMap.Empty()); + DALI_TEST_EQUALS(0u, indexedMap.size(), TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.begin() == indexedMap.end()); + DALI_TEST_CHECK(indexedMap.empty()); + + // phase 1 - Regist two element + DALI_TEST_CHECK(indexedMap.Register(keyFirst, 1)); + DALI_TEST_CHECK(indexedMap.Register(keySecond, 2)); + + // Get data by key + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + DALI_TEST_CHECK(!indexedMap.Empty()); + IndexedMapGetValueTest(indexedMap, keyFirst, true, 1, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, true, 2, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, false, 0, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, false, 0, TEST_LOCATION); + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 1, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 2, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 1, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 2, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedIntegerMap::KeyElementPairType(keyFirst, 1)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap::KeyElementPairType(keySecond, 2)); + + // Const iteration check + for(const auto& elem : indexedMap) + { + if(elem.first == keyFirst) + { + DALI_TEST_EQUALS(elem.second, 1, TEST_LOCATION); + } + else if(elem.first == keySecond) + { + DALI_TEST_EQUALS(elem.second, 2, TEST_LOCATION); + } + else + { + DALI_TEST_CHECK(false); // Should not get here + } + } + + // Iteration and fix data check + for(auto&& elem : indexedMap) + { + if(elem.first == keyFirst) + { + elem.second += 110; + } + } + // operator[] fix data check + indexedMap[keySecond] += 220; + + // Get data by key + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, true, 111, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, true, 222, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, false, 0, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, false, 0, TEST_LOCATION); + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedIntegerMap::KeyElementPairType(keyFirst, 111)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap::KeyElementPairType(keySecond, 222)); + + // Const iteration check + for(const auto& elem : indexedMap) + { + if(elem.first == keyFirst) + { + DALI_TEST_EQUALS(elem.second, 111, TEST_LOCATION); + } + else if(elem.first == keySecond) + { + DALI_TEST_EQUALS(elem.second, 222, TEST_LOCATION); + } + else + { + DALI_TEST_CHECK(false); // Should not get here + } + } + + // phase 2 - Regist two more element + DALI_TEST_CHECK(!indexedMap.Register(keyFirst, 11)); // Register failed when we try to insert data with same key + DALI_TEST_CHECK(!indexedMap.Register(keySecond, 22)); // Register failed when we try to insert data with same key + DALI_TEST_CHECK(indexedMap.Register(keyThird, 3)); + DALI_TEST_CHECK(indexedMap.Register(keyFourth, 4)); + + // Get data by key + DALI_TEST_EQUALS(4, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, true, 111, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, true, 222, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, true, 3, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, true, 4, TEST_LOCATION); + + // Get elemnt as l-value + { + auto iter = indexedMap.Get(keyFourth); + DALI_TEST_CHECK(iter != indexedMap.end()) + { + iter->second = 444; + } + } + + // Get data by index + DALI_TEST_EQUALS(indexedMap[keyFirst], 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keySecond], 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keyThird], 3, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap[keyFourth], 444, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(0), 111, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(1), 222, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(2), 3, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetElementByIndex(3), 444, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(0), keyFirst, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(1), keySecond, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(2), keyThird, TEST_LOCATION); + DALI_TEST_EQUALS(indexedMap.GetKeyByIndex(3), keyFourth, TEST_LOCATION); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(0) == IndexedIntegerMap::KeyElementPairType(keyFirst, 111)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap::KeyElementPairType(keySecond, 222)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(2) == IndexedIntegerMap::KeyElementPairType(keyThird, 3)); + DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(3) == IndexedIntegerMap::KeyElementPairType(keyFourth, 444)); + + // For coverage + DALI_TEST_EQUALS(const_cast&>(indexedMap)[keyFirst], 111, TEST_LOCATION); + + // Clear check + DALI_TEST_CHECK(!indexedMap.Empty()); + indexedMap.Clear(); + DALI_TEST_CHECK(indexedMap.Empty()); + DALI_TEST_EQUALS(0u, indexedMap.Count(), TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFirst, false, 1, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keySecond, false, 2, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyThird, false, 3, TEST_LOCATION); + IndexedMapGetValueTest(indexedMap, keyFourth, false, 4, TEST_LOCATION); + END_TEST; +} + +int UtcDaliIndexedIntegerMapNegative(void) +{ + tet_infoline("Negative test when IndexedIntegerMap access non-exist elements."); + + IndexedIntegerMap indexedMap; + + auto IndexedMapAssertTestWithIndex = [](IndexedIntegerMap& indexedMap, int testIndex) { + tet_printf("operator[] test"); + // Assert when try to access as const operator[] input with not registered key. + try + { + const auto& elem = const_cast&>(indexedMap)[333]; + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + // Assert when try to access as operator[] input with not registered key. + try + { + indexedMap[333] = 0; + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetElementByIndex test"); + // Assert when try to access as GetElementByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetElementByIndex(testIndex); + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetKeyByIndex test"); + // Assert when try to access as GetKeyByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetKeyByIndex(testIndex); + if(elem == 0) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + + tet_printf("GetKeyElementPairByIndex test"); + // Assert when try to access as GetKeyByIndex input with not registered index. + try + { + const auto& elem = indexedMap.GetKeyElementPairByIndex(testIndex); + if(elem == IndexedIntegerMap::KeyElementPairType(0, 0)) // Avoid build warning + { + DALI_TEST_CHECK(false); // Should not get here + } + DALI_TEST_CHECK(false); // Should not get here + } + catch(...) + { + DALI_TEST_CHECK(true); // Asserted + } + }; + // Assert test with empty indexedMap. + DALI_TEST_CHECK(indexedMap.Empty()); + IndexedMapAssertTestWithIndex(indexedMap, 0); + + // Register 2 data + DALI_TEST_CHECK(indexedMap.Register(111, 1)); + DALI_TEST_CHECK(indexedMap.Register(222, 2)); + DALI_TEST_EQUALS(2u, indexedMap.Count(), TEST_LOCATION); + IndexedMapAssertTestWithIndex(indexedMap, 2); + + // Test with always-invalid index like -1 + IndexedMapAssertTestWithIndex(indexedMap, -1); + + END_TEST; +} + +int UtcDaliIndexedIntegerMapStressTest(void) +{ + IndexedIntegerMap indexedMap; + + std::vector keyList(2 * (256 + 2)); + + // Add 256 kind keys and +- 1 + for(std::uint32_t i = 0; i < 256 + 2; i++) + { + // Intention overflow here + keyList[i] = i - 1; + keyList[i + 256 + 2] = ((i - 1) << 24) + (((i - 1) >> 8) & 15); + if(i == 1) + { + //To avoid same Key + keyList[i + 256 + 2] = 0x0f0f0f0f; + } + if(i == 257) + { + //To avoid same Key + keyList[i + 256 + 2] = 0xf0f0f0f0; + } + } + + auto IndexedMapGetValueTest = [](const IndexedIntegerMap& indexedMap, std::uint32_t key, bool registered, int element) { + const auto& iter = indexedMap.Get(key); + DALI_TEST_CHECK(!(iter == indexedMap.end()) == registered); + if(registered) + { + DALI_TEST_CHECK(iter->second == element); + } + }; + + for(std::size_t i = 0; i < keyList.size(); i++) + { + // We don't need to check whole key. Just compare near 0 and 256+2 + for(std::size_t j = 0; j < i && j < 4; j++) + { + DALI_TEST_CHECK(!indexedMap.Register(keyList[j], -j - 1)); + } + for(std::size_t j = 256; j < i && j < 256 + 6; j++) + { + DALI_TEST_CHECK(!indexedMap.Register(keyList[j], -j - 1)); + } + + // Regist i'th keylist + DALI_TEST_CHECK(indexedMap.Register(keyList[i], i)); + + // We don't need to check whole key. Just compare near 0 and 256+2 and end and i + for(std::size_t j = 0; j < keyList.size() && j < 20; j++) + { + IndexedMapGetValueTest(indexedMap, keyList[j], j <= i, j); + } + for(std::size_t j = 256 - 18; j < keyList.size() && j < 256 + 22; j++) + { + IndexedMapGetValueTest(indexedMap, keyList[j], j <= i, j); + } + for(std::size_t j = keyList.size() - 20; j < keyList.size(); j++) + { + IndexedMapGetValueTest(indexedMap, keyList[j], j <= i, j); + } + // When i < 20 overflow occured, but dont care. + for(std::size_t j = i - 20; j < keyList.size() && j < i + 20; j++) + { + IndexedMapGetValueTest(indexedMap, keyList[j], j <= i, j); + } + + // Keylist have over 500 kind of keys. Print debug rarely. + if(i % 50 == 0) + { + tet_printf("%u / %u pass\n", i, keyList.size()); + } + } + + END_TEST; +} diff --git a/dali/internal/common/indexed-const-string-map.h b/dali/internal/common/indexed-const-string-map.h new file mode 100644 index 0000000..239e7fe --- /dev/null +++ b/dali/internal/common/indexed-const-string-map.h @@ -0,0 +1,182 @@ +#ifndef DALI_INDEXED_CONST_STRING_MAP_H +#define DALI_INDEXED_CONST_STRING_MAP_H + +/* + * Copyright (c) 2022 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. + */ + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Internal +{ +/** + * @brief Specific key-element container which can access by index when key is Dali::Internal::ConstString. + * Register element by key. and Get element by key or index. + * + * Register operation return false when already same key registered. + * Get operation return iterator of this container. + * + * Actually, ConstString type did comparision-and-compare with known strings internally. + * That mean, we can assume that ConstString already hashed as const char* type. (== std::size_t) + * + * This container just hold const char* type keys in increase order, and binary search. + * This system have panalty when insert / delete. and have benefit when search. + * + * @note : Current IndexedConstStringMap allow only for single element per key. + * And also, did not allow to Unregister operation. + * + * @note Time complexity : + * Register() : O(ConstString converting time + Number of data) + * Get() : O(ConstString converting time + log(Number of data)) + * + * @tparam ElementType The type of the data that the container holds + */ +template +class IndexedConstStringMap : public IndexedMapBase +{ +public: + using iterator = typename IndexedMapBase::iterator; + using const_iterator = typename IndexedMapBase::const_iterator; + +public: // override + /** + * @brief Constructor. + */ + IndexedConstStringMap() + : IndexedMapBase() + { + } + + /** + * @copydoc IndexedMapBase::Clear() + */ + void Clear() override + { + mKeyElementPool.clear(); + mCharPtrIndexList.clear(); + } + +public: // Main API + /** + * @brief Register element by the ConstString key. + * + * @param[in] key The ConstString key that this container will hold. Duplicated key doesn't allow. + * @param[in] element The element pairwise with key. + * @return True if Register success. Otherwise, return false. + */ + bool Register(const ConstString& key, const ElementType& element) override + { + // Let's make key as compareable type. + const char* comparableKey = key.GetCString(); + + // Find key with binary search. + // We can do binary search cause mCharPtrIndexList is sorted. + const auto& iter = std::lower_bound(mCharPtrIndexList.cbegin(), mCharPtrIndexList.cend(), std::pair(comparableKey, 0u)); + + if(iter == mCharPtrIndexList.cend() || iter->first != comparableKey) + { + // Emplace new element back. + std::uint32_t newElementIndex = mKeyElementPool.size(); + mKeyElementPool.emplace_back(key, element); + + // Add new index into mCharPtrIndexList. + mCharPtrIndexList.insert(iter, std::pair(comparableKey, newElementIndex)); + + // Append element as child + return true; + } + else + { + // Else, duplicated key! + return false; + } + } + + /** + * @brief Get element by the ConstString key. + * + * @param[in] key The ConstString key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + iterator Get(const ConstString& key) override + { + // Let's make key as compareable type. + const char* comparableKey = key.GetCString(); + + // Find key with binary search. + // We can do binary search cause mCharPtrIndexList is sorted. + const auto& iter = std::lower_bound(mCharPtrIndexList.cbegin(), mCharPtrIndexList.cend(), std::pair(comparableKey, 0u)); + + if(iter == mCharPtrIndexList.cend() || iter->first != comparableKey) + { + // Key doesn't exist! + return this->End(); + } + + // We found it! + // iter->second will be the index of elements. + return this->Begin() + (iter->second); + } + + /** + * @brief Get element by the ConstString key. + * + * @param[in] key The ConstString key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + const_iterator Get(const ConstString& key) const override + { + // Let's make key as compareable type. + const char* comparableKey = key.GetCString(); + + // Find key with binary search. + // We can do binary search cause mCharPtrIndexList is sorted. + const auto& iter = std::lower_bound(mCharPtrIndexList.cbegin(), mCharPtrIndexList.cend(), std::pair(comparableKey, 0u)); + + if(iter == mCharPtrIndexList.cend() || iter->first != comparableKey) + { + // Key doesn't exist! + return this->End(); + } + + // We found it! + // iter->second will be the index of elements. + return this->Begin() + (iter->second); + } + +private: + /** + * @brief Convert from char* to index of container. + * + * @note mCharPtrIndexList's key should be increase order compare as std::size_t. + */ + std::vector> mCharPtrIndexList{}; + +protected: + /** + * @brief Member values from base class. + */ + using IndexedMapBase::mKeyElementPool; +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_INDEXED_CONST_STRING_MAP_H diff --git a/dali/internal/common/indexed-integer-map.h b/dali/internal/common/indexed-integer-map.h new file mode 100644 index 0000000..57130db --- /dev/null +++ b/dali/internal/common/indexed-integer-map.h @@ -0,0 +1,169 @@ +#ifndef DALI_INDEXED_INTEGER_MAP_H +#define DALI_INDEXED_INTEGER_MAP_H + +/* + * Copyright (c) 2022 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. + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Internal +{ +/** + * @brief Specific key-element container which can access by index when key is std::uint32_t. + * Register element by key. and Get element by key or index. + * + * Register operation return false when already same key registered. + * Get operation return iterator of this container. + * + * This container hold integer keys in increase order, and binary search. + * This system have panalty when insert / delete. and have benefit when search. + * + * @note : Current IndexedIntegerMap allow only for single element per key. + * And also, did not allow to Unregister operation. + * + * @note Time complexity : + * Register() : O(Number of data) + * Get() : O(log(Number of data)) + * + * @tparam ElementType The type of the data that the container holds + */ +template +class IndexedIntegerMap : public IndexedMapBase +{ +public: + using iterator = typename IndexedMapBase::iterator; + using const_iterator = typename IndexedMapBase::const_iterator; + +public: // override + /** + * @brief Constructor. + */ + IndexedIntegerMap() + : IndexedMapBase() + { + } + + /** + * @copydoc IndexedMapBase::Clear() + */ + void Clear() override + { + mKeyElementPool.clear(); + mKeyIndexList.clear(); + } + +public: // Main API + /** + * @brief Register element by the integer key. + * + * @param[in] key The integer key that this container will hold. Duplicated key doesn't allow. + * @param[in] element The element pairwise with key. + * @return True if Register success. Otherwise, return false. + */ + bool Register(const std::uint32_t& key, const ElementType& element) override + { + // Find key with binary search. + // We can do binary search cause mKeyIndexList is sorted. + const auto& iter = std::lower_bound(mKeyIndexList.cbegin(), mKeyIndexList.cend(), std::pair(key, 0u)); + + if(iter == mKeyIndexList.cend() || iter->first != key) + { + // Emplace new element back. + std::uint32_t newElementIndex = mKeyElementPool.size(); + mKeyElementPool.emplace_back(key, element); + + // Add new index into mKeyIndexList list. + mKeyIndexList.insert(iter, std::pair(key, newElementIndex)); + + // Append element as child + return true; + } + else + { + // Else, duplicated key! + return false; + } + } + + /** + * @brief Get element by the integer key. + * + * @param[in] key The integer key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + iterator Get(const std::uint32_t& key) override + { + // Find key with binary search. + // We can do binary search cause mKeyIndexList is sorted. + const auto& iter = std::lower_bound(mKeyIndexList.cbegin(), mKeyIndexList.cend(), std::pair(key, 0u)); + + if(iter == mKeyIndexList.cend() || iter->first != key) + { + // Key doesn't exist! + return this->End(); + } + + // We found it! + // iter->second will be the index of elements. + return this->Begin() + (iter->second); + } + + /** + * @brief Get element by the integer key. + * + * @param[in] key The integer key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + const_iterator Get(const std::uint32_t& key) const override + { + // Find key with binary search. + // We can do binary search cause mKeyIndexList is sorted. + const auto& iter = std::lower_bound(mKeyIndexList.cbegin(), mKeyIndexList.cend(), std::pair(key, 0u)); + + if(iter == mKeyIndexList.cend() || iter->first != key) + { + // Key doesn't exist! + return this->End(); + } + + // We found it! + // iter->second will be the index of elements. + return this->Begin() + (iter->second); + } + +private: + /** + * @brief Convert from Key to index of container. + * + * @note mKeyIndexList's key should be increase order. + */ + std::vector> mKeyIndexList{}; + +protected: + /** + * @brief Member values from base class. + */ + using IndexedMapBase::mKeyElementPool; +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_INDEXED_INTEGER_MAP_H diff --git a/dali/internal/common/indexed-map-base.h b/dali/internal/common/indexed-map-base.h new file mode 100644 index 0000000..8f80100 --- /dev/null +++ b/dali/internal/common/indexed-map-base.h @@ -0,0 +1,398 @@ +#ifndef DALI_INDEXED_MAP_BASE_H +#define DALI_INDEXED_MAP_BASE_H + +/* + * Copyright (c) 2022 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 +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Internal +{ +/** + * @brief Specific key-element container which can access by index. + * Register element by key. and Get element by key or index. + * + * This basical member API that indexed map container needs. + * Indexed map container can only Register and not allow Unregister in current implement spec. + * + * This container hold std::pair. + * Iterator will iterate this pair container. + * + * For example, + * @code + * TrieContainerBase container; + * for(auto && elements : container) + * { + * elements.first == KeyType(); + * elements.second == ElementType(); + * } + * @endcode + * + * Contain elements in registered order. + * You can access that data by this order as 'index' + * + * For example, + * @code + * container.Register(10001, 111); + * container.Register(20002, 222); + * container[10001] == 111; + * container[20002] == 222; + * container.GetElementByIndex(0) == 111; + * container.GetKeyByIndex(0) == 10001; + * container.GetKeyElementPairByIndex(1) == KeyElementPairType(20002, 222); + * @endcode + * + * Get API return iterator of container. + * + * For example, + * @code + * container.Register(10001, 111); + * const auto& iter = container.Get(10001); + * iter->first == 10001; + * iter->second == 111; + * container.Get(30003) == container.End(); + * @endcode + * + * @tparam KeyType The type of the key that the container holds. + * @tparam SearchKeyType The type of the key when the container register or get. + * @tparam ElementType The type of the data that the container holds. + */ +template +class IndexedMapBase +{ +public: + /** + * @brief Type definitions. + */ + using KeyElementPairType = std::pair; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + +public: // Virtual API + /** + * @brief Register element by the key. + * + * @param[in] key The key that this container will hold. Duplicated key doesn't allow. + * @param[in] element The element pairwise with key. + * @return True if Register success. Otherwise, return false. + */ + virtual bool Register(const SearchKeyType& key, const ElementType& element) = 0; + + /** + * @brief Get element by the key. + * + * @param[in] key The key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + virtual iterator Get(const SearchKeyType& key) = 0; + + /** + * @brief Get element by the key. + * + * @param[in] key The key that this container will hold. + * @return If exist, iterator of container. Otherwise, return End(). + */ + virtual const_iterator Get(const SearchKeyType& key) const = 0; + +public: + /** + * @brief Constructor. + */ + IndexedMapBase() + { + Clear(); + } + + /** + * @brief Destructor. + */ + virtual ~IndexedMapBase() + { + mKeyElementPool.clear(); + } + + /** + * @brief Clear this container. + */ + virtual void Clear() + { + mKeyElementPool.clear(); + } + + /** + * @brief Get the number of elements that this container hold. + * + * @return The number of elements that this container hold. + */ + std::size_t Count() const + { + return mKeyElementPool.size(); + } + + /** + * @brief Check whether container is empty or not. + * + * @return Whether elemnt is empty or not. + */ + bool Empty() const + { + return mKeyElementPool.empty(); + } + + /** + * @brief Reserve KeyElementPool container size. + * Reserve only if current container size is smaller than input size. + * + * @param[in] size Reserve size. + */ + void Reserve(const std::size_t& size) + { + if(mKeyElementPool.size() < size) + { + mKeyElementPool.reserve(size); + } + } + + /** + * @brief Get Element by the key. + * @note Assert throw when try to use unregistered key. + * + * @param[in] key The key what we want to get. + * @return registered element. + */ + const ElementType& operator[](const SearchKeyType& key) const + { + const_iterator iter = Get(key); + DALI_ASSERT_ALWAYS(iter != End() && "const operator[] doesn't allow non-exist key access"); + return iter->second; + } + + /** + * @brief Get Element by the key. + * @note Assert throw when try to use unregistered key. + * + * @param[in] key The key what we want to get. + * @return registered element. + */ + ElementType& operator[](const SearchKeyType& key) + { + iterator iter = Get(key); + DALI_ASSERT_ALWAYS(iter != End() && "operator[] doesn't allow non-exist key access"); + return iter->second; + } + + /** + * @brief Get Element by the index. + * + * @param[in] index The index what we want to get. + * @return index'th registered element. + * @note mTrieKeyElementPool emplace_back the elements ordered by Register function called. + */ + const ElementType& GetElementByIndex(const std::uint32_t& index) const + { + DALI_ASSERT_ALWAYS((index < mKeyElementPool.size()) && "operator[] index >= Count()"); + return mKeyElementPool[index].second; + } + + /** + * @brief Get Key by the index. + * + * @param[in] index The index what we want to get. + * @return index'th registered key. + * @note mTrieKeyElementPool emplace_back the elements ordered by Register function called. + */ + const KeyType& GetKeyByIndex(const std::uint32_t& index) const + { + DALI_ASSERT_ALWAYS((index < mKeyElementPool.size()) && "operator[] index >= Count()"); + return mKeyElementPool[index].first; + } + + /** + * @brief Get Key and Element by the index. + * + * @param[in] index The index what we want to get. + * @return index'th registered key element pair. + * @note mTrieKeyElementPool emplace_back the elements ordered by Register function called. + */ + const KeyElementPairType& GetKeyElementPairByIndex(const std::uint32_t& index) const + { + DALI_ASSERT_ALWAYS((index < mKeyElementPool.size()) && "operator[] index >= Count()"); + return mKeyElementPool[index]; + } + + /** + * @brief Iterator to the beginning of the data. + * @return Iterator to the beginning of the data + */ + iterator Begin() + { + return mKeyElementPool.begin(); + } + /** + * @brief Const Iterator to the beginning of the data. + * @return Const Iterator to the beginning of the data + */ + const_iterator CBegin() const + { + return mKeyElementPool.cbegin(); + } + /** + * @brief Const Iterator to the beginning of the data. + * @return Const Iterator to the beginning of the data + */ + const_iterator Begin() const + { + return mKeyElementPool.begin(); + } + + /** + * @brief Iterator to the end of the data (one past last element). + * @return Iterator to the end of the data (one past last element) + */ + iterator End() + { + return mKeyElementPool.end(); + } + /** + * @brief Const iterator to the end of the data (one past last element). + * @return Const iterator to the end of the data (one past last element) + */ + const_iterator CEnd() const + { + return mKeyElementPool.cend(); + } + /** + * @brief Const iterator to the end of the data (one past last element). + * @return Const iterator to the end of the data (one past last element) + */ + const_iterator End() const + { + return mKeyElementPool.end(); + } + +public: // API for C++11 std style functions. + /** + * Support for C++11 std style function call. + * @see Clear() + */ + void clear() + { + Clear(); + } + + /** + * Support for C++11 std style function call. + * + * @return The number of elements that this container hold. + * @see Count() + */ + std::size_t size() const + { + return Count(); + } + + /** + * Support for C++11 std style function call. + * + * @return Whether elemnt is empty or not. + * @see Empty() + */ + bool empty() const + { + return Empty(); + } + + /** + * Support for C++11 std style function call. + * + * @param[in] size Reserve size. + * @see Reserve() + */ + void reserve(const std::size_t size) + { + Reserve(size); + } + + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The start iterator + */ + iterator begin() + { + return Begin(); + } + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The start const iterator + */ + const_iterator cbegin() const + { + return CBegin(); + } + + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The start const iterator + */ + const_iterator begin() const + { + return Begin(); + } + + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The end iterator + */ + iterator end() + { + return End(); + } + + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The end const iterator + */ + const_iterator cend() const + { + return CEnd(); + } + + /** + * Support for C++11 Range-based for loop: for( item : container ). + * @return The end const iterator + */ + const_iterator end() const + { + return End(); + } + +protected: + std::vector mKeyElementPool; +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_INDEXED_MAP_BASE_H diff --git a/dali/internal/event/common/type-info-impl.cpp b/dali/internal/event/common/type-info-impl.cpp index 43c68a9..7133dce 100644 --- a/dali/internal/event/common/type-info-impl.cpp +++ b/dali/internal/event/common/type-info-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -215,8 +215,11 @@ bool TypeInfo::DoActionTo(BaseObject* object, const std::string& actionName, con { bool done = false; - ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder(actionName)); - +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + auto iter = mActions.Get(ConstString(actionName)); +#else + ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder(actionName)); +#endif if(iter != mActions.end()) { done = (iter->second)(object, actionName, properties); @@ -238,8 +241,11 @@ bool TypeInfo::ConnectSignal(BaseObject* object, ConnectionTrackerInterface* con { bool connected(false); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + auto iter = mSignalConnectors.Get(ConstString(signalName)); +#else ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder(signalName)); - +#endif if(iter != mSignalConnectors.end()) { connected = (iter->second)(object, connectionTracker, signalName, functor); @@ -292,7 +298,11 @@ std::string TypeInfo::GetActionName(uint32_t index) const if(index < count) { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + name = std::string(mActions.GetKeyByIndex(index).GetStringView()); +#else name = mActions[index].first; +#endif } else { @@ -326,7 +336,11 @@ std::string TypeInfo::GetSignalName(uint32_t index) const if(index < count) { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + name = std::string(mSignalConnectors.GetKeyByIndex(index).GetStringView()); +#else name = mSignalConnectors[index].first; +#endif } else { @@ -391,7 +405,11 @@ void TypeInfo::AppendProperties(Dali::Property::IndexContainer& ind std::string_view TypeInfo::GetRegisteredPropertyName(Property::Index index) const { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#endif if(iter != mRegisteredProperties.end()) { return iter->second.name.GetStringView(); @@ -419,7 +437,11 @@ std::string_view TypeInfo::GetPropertyName(Property::Index index) const } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#endif if(iter != mRegisteredProperties.end()) { return iter->second.name.GetStringView(); @@ -446,7 +468,13 @@ void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionF } else { - ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(), PairFinder(actionName)); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mActions.Register(ConstString(actionName), function)) + { + DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str()); + } +#else + ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(), PairFinder(actionName)); if(iter == mActions.end()) { @@ -456,6 +484,7 @@ void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionF { DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str()); } +#endif } } @@ -467,6 +496,12 @@ void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::Sign } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mSignalConnectors.Register(ConstString(signalName), function)) + { + DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str()); + } +#else ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder(signalName)); if(iter == mSignalConnectors.end()) @@ -477,6 +512,7 @@ void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::Sign { DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str()); } +#endif } } @@ -490,8 +526,13 @@ void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Ty } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mRegisteredProperties.Register(static_cast(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))) + { + DALI_ASSERT_ALWAYS(!"Property index already added to Type"); + } +#else RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - if(iter == mRegisteredProperties.end()) { mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))); @@ -500,6 +541,7 @@ void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Ty { DALI_ASSERT_ALWAYS(!"Property index already added to Type"); } +#endif } } @@ -513,8 +555,13 @@ void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Ty } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mRegisteredProperties.Register(static_cast(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))) + { + DALI_ASSERT_ALWAYS(!"Property index already added to Type"); + } +#else RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - if(iter == mRegisteredProperties.end()) { mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))); @@ -523,13 +570,19 @@ void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Ty { DALI_ASSERT_ALWAYS(!"Property index already added to Type"); } +#endif } } void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Type type) { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mRegisteredProperties.Register(static_cast(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))) + { + DALI_ASSERT_ALWAYS(!"Property index already added to Type"); + } +#else RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - if(iter == mRegisteredProperties.end()) { mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))); @@ -538,12 +591,22 @@ void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Pr { DALI_ASSERT_ALWAYS(!"Property index already added to Type"); } +#endif } void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Value defaultValue) { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mRegisteredProperties.Register(static_cast(index), RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))) + { + DALI_ASSERT_ALWAYS(!"Property index already added to Type"); + } + else + { + mPropertyDefaultValues.Register(static_cast(index), std::move(defaultValue)); + } +#else RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - if(iter == mRegisteredProperties.end()) { mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))); @@ -553,6 +616,7 @@ void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Pr { DALI_ASSERT_ALWAYS(!"Property index already added to Type"); } +#endif } void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index index, Property::Index baseIndex, uint32_t componentIndex) @@ -562,8 +626,19 @@ void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index bool success = false; - RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(mRegisteredProperties.Get(static_cast(index)) == mRegisteredProperties.end()) + { + const auto& iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder(baseIndex, componentIndex)); + if(iter == mRegisteredProperties.end()) + { + mRegisteredProperties.Register(static_cast(index), RegisteredProperty(type, ConstString(name), baseIndex, componentIndex)); + success = true; + } + } +#else + RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); if(iter == mRegisteredProperties.end()) { iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder(baseIndex, componentIndex)); @@ -574,19 +649,23 @@ void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index success = true; } } +#endif DALI_ASSERT_ALWAYS(success && "Property component already registered"); } void TypeInfo::AddChildProperty(std::string name, Property::Index index, Property::Type type) { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + if(!mRegisteredChildProperties.Register(static_cast(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))) +#else RegisteredPropertyContainer::iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder(index)); - if(iter == mRegisteredChildProperties.end()) { mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX))); } else +#endif { DALI_ASSERT_ALWAYS(!"Property index already added to Type"); } @@ -646,8 +725,11 @@ Property::Index TypeInfo::GetBasePropertyIndex(Property::Index index) const { Property::Index basePropertyIndex = Property::INVALID_INDEX; +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - +#endif if(iter != mRegisteredProperties.end()) { basePropertyIndex = iter->second.basePropertyIndex; @@ -665,8 +747,11 @@ int32_t TypeInfo::GetComponentIndex(Property::Index index) const { int componentIndex = Property::INVALID_COMPONENT_INDEX; +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - +#endif if(iter != mRegisteredProperties.end()) { componentIndex = iter->second.componentIndex; @@ -702,8 +787,11 @@ Property::Index TypeInfo::GetChildPropertyIndex(ConstString name) const std::string_view TypeInfo::GetChildPropertyName(Property::Index index) const { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredChildProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder(index)); - +#endif if(iter != mRegisteredChildProperties.end()) { return iter->second.name.GetStringView(); @@ -724,8 +812,11 @@ Property::Type TypeInfo::GetChildPropertyType(Property::Index index) const { Property::Type type(Property::NONE); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredChildProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder(index)); - +#endif if(iter != mRegisteredChildProperties.end()) { type = iter->second.type; @@ -760,7 +851,11 @@ bool TypeInfo::IsPropertyWritable(Property::Index index) const } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#endif if(iter != mRegisteredProperties.end()) { writable = iter->second.setFunc ? true : false; @@ -875,8 +970,11 @@ Property::Type TypeInfo::GetPropertyType(Property::Index index) const } else { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); - +#endif if(iter != mRegisteredProperties.end()) { if(iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX) @@ -911,7 +1009,11 @@ Property::Type TypeInfo::GetPropertyType(Property::Index index) const Property::Value TypeInfo::GetPropertyDefaultValue(Property::Index index) const { +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mPropertyDefaultValues.Get(static_cast(index)); +#else PropertyDefaultValueContainer::const_iterator iter = find_if(mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(), PairFinder(index)); +#endif if(iter != mPropertyDefaultValues.end()) { return iter->second; @@ -927,7 +1029,11 @@ Property::Value TypeInfo::GetPropertyDefaultValue(Property::Index index) const void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property::Value value) const { - RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else + RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#endif if(iter != mRegisteredProperties.end()) { if(iter->second.setFunc) @@ -958,6 +1064,7 @@ void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property:: void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const { + // Slow but should not be done that often RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder(ConstString(name))); if(iter != mRegisteredProperties.end()) { @@ -986,7 +1093,11 @@ void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property Property::Value TypeInfo::GetProperty(const BaseObject* object, Property::Index index) const { - RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + const auto& iter = mRegisteredProperties.Get(static_cast(index)); +#else + RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder(index)); +#endif if(iter != mRegisteredProperties.end()) { if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value diff --git a/dali/internal/event/common/type-info-impl.h b/dali/internal/event/common/type-info-impl.h index fbdf04d..37c43ed 100644 --- a/dali/internal/event/common/type-info-impl.h +++ b/dali/internal/event/common/type-info-impl.h @@ -1,8 +1,9 @@ #ifndef DALI_INTERNAL_TYPE_INFO_H #define DALI_INTERNAL_TYPE_INFO_H +#define USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO /// For safety. If some problem occured, just remove this define. /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -22,6 +23,11 @@ #include // INTERNAL INCLUDES +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO +#include +#include +#endif + #include #include #include @@ -380,15 +386,27 @@ private: int32_t componentIndex = Property::INVALID_COMPONENT_INDEX; }; - using ConnectionPair = std::pair; - using ActionPair = std::pair; - using RegisteredPropertyPair = std::pair; - using PropertyDefaultValuePair = std::pair; - + using ActionPair = std::pair; + using ConnectionPair = std::pair; +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + using RegisteredPropertyPair = std::pair; + using PropertyDefaultValuePair = std::pair; +#else + using RegisteredPropertyPair = std::pair; + using PropertyDefaultValuePair = std::pair; +#endif + +#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO + using ActionContainer = Dali::Internal::IndexedConstStringMap; + using ConnectorContainer = Dali::Internal::IndexedConstStringMap; + using RegisteredPropertyContainer = Dali::Internal::IndexedIntegerMap; + using PropertyDefaultValueContainer = Dali::Internal::IndexedIntegerMap; +#else using ActionContainer = std::vector; using ConnectorContainer = std::vector; using RegisteredPropertyContainer = std::vector; using PropertyDefaultValueContainer = std::vector; +#endif /** * Append properties from registeredProperties onto indices. diff --git a/dali/internal/event/common/type-registry-impl.cpp b/dali/internal/event/common/type-registry-impl.cpp index c04373f..73fc652 100644 --- a/dali/internal/event/common/type-registry-impl.cpp +++ b/dali/internal/event/common/type-registry-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -55,15 +55,12 @@ TypeRegistry::~TypeRegistry() TypeRegistry::TypeInfoPointer TypeRegistry::GetTypeInfo(const std::string& uniqueTypeName) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(uniqueTypeName)); + if(iter != mRegistryLut.end()) { - // Note! mRegistryLut contains Dali::TypeInfo handles, so cannot call GetTypeName() - // as it calls us back resulting in infinite loop (GetTypeName is in BaseHandle part) - if(iter->GetName() == uniqueTypeName) - { - return iter; - } + return iter->second; } + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Cannot find requested type '%s'\n", uniqueTypeName.c_str()); return TypeRegistry::TypeInfoPointer(); @@ -87,7 +84,7 @@ const std::string& TypeRegistry::GetTypeName(uint32_t index) const if(index < mRegistryLut.size()) { - return mRegistryLut[index]->GetName(); + return mRegistryLut.GetElementByIndex(index)->GetName(); } return EMPTY_STRING; @@ -124,19 +121,12 @@ std::string TypeRegistry::Register(std::string uniqueTypeName { std::string baseTypeName = DemangleClassName(baseTypeInfo.name()); - // check for duplicates using uniqueTypeName - for(auto&& iter : mRegistryLut) + if(!mRegistryLut.Register(ConstString(uniqueTypeName), new Internal::TypeInfo(uniqueTypeName, baseTypeName, createInstance, defaultProperties, defaultPropertyCount))) { - if(iter->GetName() == uniqueTypeName) - { - DALI_LOG_WARNING("Duplicate name in TypeRegistry for '%s'\n", +uniqueTypeName.c_str()); - DALI_ASSERT_ALWAYS(!"Duplicate type name in Type Registration"); - return uniqueTypeName; // never actually happening due to the assert - } + DALI_LOG_WARNING("Duplicate name in TypeRegistry for '%s'\n", +uniqueTypeName.c_str()); + DALI_ASSERT_ALWAYS(!"Duplicate type name in Type Registration"); + return uniqueTypeName; // never actually happening due to the assert } - - mRegistryLut.push_back(TypeRegistry::TypeInfoPointer( - new Internal::TypeInfo(uniqueTypeName, baseTypeName, createInstance, defaultProperties, defaultPropertyCount))); DALI_LOG_INFO(gLogFilter, Debug::Concise, "Type Registration %s(%s)\n", uniqueTypeName.c_str(), baseTypeName.c_str()); if(callCreateOnInit) @@ -151,18 +141,12 @@ void TypeRegistry::Register(std::string uniqueTypeName, const std::type_info& ba { std::string baseTypeName = DemangleClassName(baseTypeInfo.name()); - // check for duplicates using uniqueTypeName - for(auto&& iter : mRegistryLut) + if(!mRegistryLut.Register(ConstString(uniqueTypeName), TypeRegistry::TypeInfoPointer(new Internal::TypeInfo(uniqueTypeName, baseTypeName, createInstance)))) { - if(iter->GetName() == uniqueTypeName) - { - DALI_LOG_WARNING("Duplicate name in TypeRegistry for '%s'\n", +uniqueTypeName.c_str()); - DALI_ASSERT_ALWAYS(!"Duplicate type name in Type Registration"); - return; // never actually happening due to the assert - } + DALI_LOG_WARNING("Duplicate name in TypeRegistry for '%s'\n", +uniqueTypeName.c_str()); + DALI_ASSERT_ALWAYS(!"Duplicate type name in Type Registration"); + return; // never actually happening due to the assert } - - mRegistryLut.push_back(TypeRegistry::TypeInfoPointer(new Internal::TypeInfo(uniqueTypeName, baseTypeName, createInstance))); DALI_LOG_INFO(gLogFilter, Debug::Concise, "Type Registration %s(%s)\n", uniqueTypeName.c_str(), baseTypeName.c_str()); } @@ -181,52 +165,42 @@ std::string TypeRegistry::RegistrationName(const std::type_info& registerType) void TypeRegistry::RegisterSignal(TypeRegistration& typeRegistration, std::string name, Dali::TypeInfo::SignalConnectorFunction func) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddConnectorFunction(std::move(name), func); - break; - } + iter->second->AddConnectorFunction(std::move(name), func); } } bool TypeRegistry::RegisterAction(TypeRegistration& typeRegistration, std::string name, Dali::TypeInfo::ActionFunction f) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddActionFunction(std::move(name), f); - return true; - } + iter->second->AddActionFunction(std::move(name), f); + return true; } return false; } bool TypeRegistry::RegisterProperty(TypeRegistration& typeRegistration, std::string name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddProperty(std::move(name), index, type, setFunc, getFunc); - return true; - } + iter->second->AddProperty(std::move(name), index, type, setFunc, getFunc); + return true; } - return false; } bool TypeRegistry::RegisterProperty(const std::string& objectName, std::string name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(objectName)); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == objectName) - { - iter->AddProperty(std::move(name), index, type, setFunc, getFunc); - return true; - } + iter->second->AddProperty(std::move(name), index, type, setFunc, getFunc); + return true; } return false; @@ -234,13 +208,11 @@ bool TypeRegistry::RegisterProperty(const std::string& objectName, std::string n bool TypeRegistry::RegisterAnimatableProperty(TypeRegistration& typeRegistration, std::string name, Property::Index index, Property::Type type) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddAnimatableProperty(std::move(name), index, type); - return true; - } + iter->second->AddAnimatableProperty(std::move(name), index, type); + return true; } return false; @@ -248,13 +220,11 @@ bool TypeRegistry::RegisterAnimatableProperty(TypeRegistration& typeRegistration bool TypeRegistry::RegisterAnimatableProperty(TypeRegistration& typeRegistration, std::string name, Property::Index index, Property::Value value) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddAnimatableProperty(std::move(name), index, std::move(value)); - return true; - } + iter->second->AddAnimatableProperty(std::move(name), index, std::move(value)); + return true; } return false; @@ -262,13 +232,11 @@ bool TypeRegistry::RegisterAnimatableProperty(TypeRegistration& typeRegistration bool TypeRegistry::RegisterAnimatablePropertyComponent(TypeRegistration& typeRegistration, std::string name, Property::Index index, Property::Index baseIndex, unsigned int componentIndex) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(typeRegistration.RegisteredName())); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == typeRegistration.RegisteredName()) - { - iter->AddAnimatablePropertyComponent(std::move(name), index, baseIndex, componentIndex); - return true; - } + iter->second->AddAnimatablePropertyComponent(std::move(name), index, baseIndex, componentIndex); + return true; } return false; @@ -276,13 +244,11 @@ bool TypeRegistry::RegisterAnimatablePropertyComponent(TypeRegistration& typeReg bool TypeRegistry::RegisterChildProperty(const std::string& registeredType, std::string name, Property::Index index, Property::Type type) { - for(auto&& iter : mRegistryLut) + auto iter = mRegistryLut.Get(ConstString(registeredType)); + if(iter != mRegistryLut.end()) { - if(iter->GetName() == registeredType) - { - iter->AddChildProperty(std::move(name), index, type); - return true; - } + iter->second->AddChildProperty(std::move(name), index, type); + return true; } return false; diff --git a/dali/internal/event/common/type-registry-impl.h b/dali/internal/event/common/type-registry-impl.h index 946e125..8437ba0 100644 --- a/dali/internal/event/common/type-registry-impl.h +++ b/dali/internal/event/common/type-registry-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_TYPE_REGISTRY_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -235,7 +236,7 @@ private: /* * Mapping from type name to TypeInfo */ - std::vector mRegistryLut; + Dali::Internal::IndexedConstStringMap mRegistryLut; std::vector mInitFunctions; -- 2.7.4