Add Internal::IndexedMap 84/270484/36
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 3 Feb 2022 07:20:06 +0000 (16:20 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 23 Feb 2022 11:15:56 +0000 (20:15 +0900)
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<std::pair<KeyType, ElementType>>::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 <eunkiki.hong@samsung.com>
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/utc-Dali-Internal-IndexedConstStringMap.cpp [new file with mode: 0644]
automated-tests/src/dali-internal/utc-Dali-Internal-IndexedIntegerMap.cpp [new file with mode: 0644]
dali/internal/common/indexed-const-string-map.h [new file with mode: 0644]
dali/internal/common/indexed-integer-map.h [new file with mode: 0644]
dali/internal/common/indexed-map-base.h [new file with mode: 0644]
dali/internal/event/common/type-info-impl.cpp
dali/internal/event/common/type-info-impl.h
dali/internal/event/common/type-registry-impl.cpp
dali/internal/event/common/type-registry-impl.h

index 64a73b5..c1a3fcb 100644 (file)
@@ -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 (file)
index 0000000..1ee223d
--- /dev/null
@@ -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 <dali-test-suite-utils.h>
+#include <dali/public-api/dali-core.h>
+
+#include <random>
+#include <string>
+
+// Internal headers are allowed here
+#include <dali/internal/common/indexed-const-string-map.h>
+
+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<std::string::size_type> 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<char>& operator<<(std::basic_ostream<char>& 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<int> 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<int> indexedMap;
+
+  auto IndexedMapGetValueTest = [](const IndexedConstStringMap<int>& 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<int>::KeyElementPairType(keyFirst, 1));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap<int>::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<int>::KeyElementPairType(keyFirst, 111));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap<int>::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<int>::KeyElementPairType(keyFirst, 111));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedConstStringMap<int>::KeyElementPairType(keySecond, 222));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(2) == IndexedConstStringMap<int>::KeyElementPairType(keyThird, 3));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(3) == IndexedConstStringMap<int>::KeyElementPairType(keyFourth, 444));
+
+  // For coverage
+  DALI_TEST_EQUALS(const_cast<const IndexedConstStringMap<int>&>(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<int> indexedMap;
+
+  auto IndexedMapAssertTestWithIndex = [](IndexedConstStringMap<int>& 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<const IndexedConstStringMap<int>&>(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<int>::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<std::string> Database;
+  Database.reserve(DB_SIZE);
+
+  IndexedConstStringMap<ConstString> constStringDB1;
+  constStringDB1.reserve(DB_SIZE);
+
+  IndexedConstStringMap<std::string> 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 (file)
index 0000000..a93748f
--- /dev/null
@@ -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 <dali-test-suite-utils.h>
+
+#include <stdlib.h>
+#include <string>
+
+#include <dali/internal/common/indexed-integer-map.h>
+
+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<int> 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<int>& 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<int>::KeyElementPairType(keyFirst, 1));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap<int>::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<int>::KeyElementPairType(keyFirst, 111));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap<int>::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<int>::KeyElementPairType(keyFirst, 111));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(1) == IndexedIntegerMap<int>::KeyElementPairType(keySecond, 222));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(2) == IndexedIntegerMap<int>::KeyElementPairType(keyThird, 3));
+  DALI_TEST_CHECK(indexedMap.GetKeyElementPairByIndex(3) == IndexedIntegerMap<int>::KeyElementPairType(keyFourth, 444));
+
+  // For coverage
+  DALI_TEST_EQUALS(const_cast<const IndexedIntegerMap<int>&>(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<int> indexedMap;
+
+  auto IndexedMapAssertTestWithIndex = [](IndexedIntegerMap<int>& 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<const IndexedIntegerMap<int>&>(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<int>::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<int> indexedMap;
+
+  std::vector<std::uint32_t> 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<int>& 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 (file)
index 0000000..239e7fe
--- /dev/null
@@ -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 <dali/internal/common/const-string.h>
+#include <dali/internal/common/indexed-map-base.h>
+
+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<typename ElementType>
+class IndexedConstStringMap : public IndexedMapBase<ConstString, ConstString, ElementType>
+{
+public:
+  using iterator       = typename IndexedMapBase<ConstString, ConstString, ElementType>::iterator;
+  using const_iterator = typename IndexedMapBase<ConstString, ConstString, ElementType>::const_iterator;
+
+public: // override
+  /**
+   * @brief Constructor.
+   */
+  IndexedConstStringMap()
+  : IndexedMapBase<ConstString, ConstString, ElementType>()
+  {
+  }
+
+  /**
+   * @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<const char*, std::uint32_t>(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<const char*, std::uint32_t>(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<const char*, std::uint32_t>(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<const char*, std::uint32_t>(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<std::pair<const char*, std::uint32_t>> mCharPtrIndexList{};
+
+protected:
+  /**
+   * @brief Member values from base class.
+   */
+  using IndexedMapBase<ConstString, ConstString, ElementType>::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 (file)
index 0000000..57130db
--- /dev/null
@@ -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 <dali/internal/common/indexed-map-base.h>
+
+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<typename ElementType>
+class IndexedIntegerMap : public IndexedMapBase<std::uint32_t, std::uint32_t, ElementType>
+{
+public:
+  using iterator       = typename IndexedMapBase<std::uint32_t, std::uint32_t, ElementType>::iterator;
+  using const_iterator = typename IndexedMapBase<std::uint32_t, std::uint32_t, ElementType>::const_iterator;
+
+public: // override
+  /**
+   * @brief Constructor.
+   */
+  IndexedIntegerMap()
+  : IndexedMapBase<std::uint32_t, std::uint32_t, ElementType>()
+  {
+  }
+
+  /**
+   * @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<std::uint32_t, std::uint32_t>(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<std::uint32_t, std::uint32_t>(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<std::uint32_t, std::uint32_t>(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<std::uint32_t, std::uint32_t>(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<std::pair<std::uint32_t, std::uint32_t>> mKeyIndexList{};
+
+protected:
+  /**
+   * @brief Member values from base class.
+   */
+  using IndexedMapBase<std::uint32_t, std::uint32_t, ElementType>::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 (file)
index 0000000..8f80100
--- /dev/null
@@ -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 <algorithm>
+#include <string>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+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<KeyType, ElementType>.
+ * Iterator will iterate this pair container.
+ *
+ * For example,
+ * @code
+ * TrieContainerBase<KeyType, SearchKeyType, KeyIndexConverterType, ElementType> 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<typename KeyType, typename SearchKeyType, typename ElementType>
+class IndexedMapBase
+{
+public:
+  /**
+   * @brief Type definitions.
+   */
+  using KeyElementPairType = std::pair<KeyType, ElementType>;
+  using iterator           = typename std::vector<KeyElementPairType>::iterator;
+  using const_iterator     = typename std::vector<KeyElementPairType>::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<KeyElementPairType> mKeyElementPool;
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif //  DALI_INDEXED_MAP_BASE_H
index 43c68a9..7133dce 100644 (file)
@@ -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<std::string, ActionPair>(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<std::string, ActionPair>(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<std::string, ConnectionPair>(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<std::uint32_t>(index));
+#else
   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::string, ActionPair>(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<std::string, ActionPair>(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<std::string, ConnectionPair>(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<std::uint32_t>(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<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(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<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(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<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(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<std::uint32_t>(index), std::move(defaultValue));
+  }
+#else
   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<Property::Index, RegisteredPropertyPair>(index));
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  if(mRegisteredProperties.Get(static_cast<std::uint32_t>(index)) == mRegisteredProperties.end())
+  {
+    const auto& iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(baseIndex, componentIndex));
 
+    if(iter == mRegisteredProperties.end())
+    {
+      mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), baseIndex, componentIndex));
+      success = true;
+    }
+  }
+#else
+  RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
   if(iter == mRegisteredProperties.end())
   {
     iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(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<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
+#else
   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<std::uint32_t>(index));
+#else
   PropertyDefaultValueContainer::const_iterator iter = find_if(mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(), PairFinder<Property::Index, PropertyDefaultValuePair>(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<Property::Index, RegisteredPropertyPair>(index));
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(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<RegisteredPropertyPair>(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<Property::Index, RegisteredPropertyPair>(index));
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
   if(iter != mRegisteredProperties.end())
   {
     if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value
index fbdf04d..37c43ed 100644 (file)
@@ -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.
 #include <string>
 
 // INTERNAL INCLUDES
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+#include <dali/internal/common/indexed-const-string-map.h>
+#include <dali/internal/common/indexed-integer-map.h>
+#endif
+
 #include <dali/devel-api/object/csharp-type-info.h>
 #include <dali/internal/common/const-string.h>
 #include <dali/internal/event/object/default-property-metadata.h>
@@ -380,15 +386,27 @@ private:
     int32_t         componentIndex    = Property::INVALID_COMPONENT_INDEX;
   };
 
-  using ConnectionPair           = std::pair<std::string, Dali::TypeInfo::SignalConnectorFunction>;
-  using ActionPair               = std::pair<std::string, Dali::TypeInfo::ActionFunction>;
-  using RegisteredPropertyPair   = std::pair<Property::Index, RegisteredProperty>;
-  using PropertyDefaultValuePair = std::pair<Property::Index, Property::Value>;
-
+  using ActionPair     = std::pair<std::string, Dali::TypeInfo::ActionFunction>;
+  using ConnectionPair = std::pair<std::string, Dali::TypeInfo::SignalConnectorFunction>;
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  using RegisteredPropertyPair   = std::pair<std::uint32_t, RegisteredProperty>;
+  using PropertyDefaultValuePair = std::pair<std::uint32_t, Property::Value>;
+#else
+  using RegisteredPropertyPair        = std::pair<Property::Index, RegisteredProperty>;
+  using PropertyDefaultValuePair      = std::pair<Property::Index, Property::Value>;
+#endif
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  using ActionContainer               = Dali::Internal::IndexedConstStringMap<Dali::TypeInfo::ActionFunction>;
+  using ConnectorContainer            = Dali::Internal::IndexedConstStringMap<Dali::TypeInfo::SignalConnectorFunction>;
+  using RegisteredPropertyContainer   = Dali::Internal::IndexedIntegerMap<RegisteredProperty>;
+  using PropertyDefaultValueContainer = Dali::Internal::IndexedIntegerMap<Property::Value>;
+#else
   using ActionContainer               = std::vector<ActionPair>;
   using ConnectorContainer            = std::vector<ConnectionPair>;
   using RegisteredPropertyContainer   = std::vector<RegisteredPropertyPair>;
   using PropertyDefaultValueContainer = std::vector<PropertyDefaultValuePair>;
+#endif
 
   /**
    * Append properties from registeredProperties onto indices.
index c04373f..73fc652 100644 (file)
@@ -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;
index 946e125..8437ba0 100644 (file)
@@ -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 <dali/devel-api/object/csharp-type-info.h>
+#include <dali/internal/common/indexed-const-string-map.h>
 #include <dali/internal/event/common/type-info-impl.h>
 #include <dali/internal/event/object/default-property-metadata.h>
 #include <dali/public-api/object/base-handle.h>
@@ -235,7 +236,7 @@ private:
   /*
    * Mapping from type name to TypeInfo
    */
-  std::vector<TypeInfoPointer> mRegistryLut;
+  Dali::Internal::IndexedConstStringMap<TypeInfoPointer> mRegistryLut;
 
   std::vector<Dali::TypeInfo::CreateFunction> mInitFunctions;