Use OrderedSet so remove useless iteration for some singletone 76/285976/30
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 23 Dec 2022 08:25:24 +0000 (17:25 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Fri, 24 Feb 2023 04:54:55 +0000 (04:54 +0000)
There was some unneccesary iteration
s.t. render-manager / animation-playlist
/ property-notification-manager / relayout-controller
hold the same object's, and remove it.

We don't need to check "Whole" objects what we hold now. So we make them use
hashed set data structure, so we can find & erase the object without iterate.

Note : OrderedSet is slow when we iterate. So, we don't make
update-manager items as OwnerSet because they iterate whole things every frame.

TODO : There was some case that duplicated called of EraseObject.
We might need to remove them.

Change-Id: I703edb0c7e1f7e01c434a3020edffeab63a861f2
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
15 files changed:
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/utc-Dali-Internal-OrderedSet.cpp [new file with mode: 0644]
dali/internal/common/ordered-set.h [new file with mode: 0644]
dali/internal/event/animation/animation-playlist.cpp
dali/internal/event/animation/animation-playlist.h
dali/internal/event/common/property-notification-impl.cpp
dali/internal/event/common/property-notification-manager.cpp
dali/internal/event/common/property-notification-manager.h
dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp
dali/internal/event/size-negotiation/memory-pool-relayout-container.h
dali/internal/event/size-negotiation/relayout-controller-impl.cpp
dali/internal/event/size-negotiation/relayout-controller-impl.h
dali/internal/render/common/render-manager.cpp
dali/internal/update/common/scene-graph-property-notification.h
dali/internal/update/manager/update-manager.cpp

index 02c9cf4..2308ba1 100644 (file)
@@ -19,6 +19,7 @@ SET(TC_SOURCES
         utc-Dali-Internal-LongPressGesture.cpp
         utc-Dali-Internal-MatrixUtils.cpp
         utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
+        utc-Dali-Internal-OrderedSet.cpp
         utc-Dali-Internal-OwnerPointer.cpp
         utc-Dali-Internal-PinchGesture.cpp
         utc-Dali-Internal-PinchGestureProcessor.cpp
diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-OrderedSet.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-OrderedSet.cpp
new file mode 100644 (file)
index 0000000..01c24ed
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2023 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 <utility>
+
+// INTERNAL INCLUDES
+#include <dali-test-suite-utils.h>
+#include <dali/internal/common/ordered-set.h>
+
+using namespace Dali::Internal;
+
+void utc_dali_internal_owner_set_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_owner_set_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+namespace
+{
+/// Takes in a reference to a bool which is set to true when the destructor is called
+class OwnedClass
+{
+public:
+  OwnedClass(bool& destructorCalled)
+  : mDestructorCalled(destructorCalled)
+  {
+    mDestructorCalled = false;
+  }
+
+  ~OwnedClass()
+  {
+    mDestructorCalled = true;
+  }
+
+private:
+  bool& mDestructorCalled;
+};
+
+/// Just a simple class with a member value and global refcount.
+class ClassWithId
+{
+public:
+  ClassWithId(int id)
+  : mId(id)
+  {
+    ++gRefCount;
+  }
+  ~ClassWithId()
+  {
+    --gRefCount;
+  }
+
+  static int gRefCount;
+  int        mId{};
+};
+int ClassWithId::gRefCount = 0;
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliOrderedSetEnsureDeletion(void)
+{
+  // Ensure that the object owned by the OrderedSet is deleted.
+
+  bool deleted = false;
+
+  {
+    OrderedSet<OwnedClass> set;
+    set.PushBack(new OwnedClass(deleted));
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  }
+
+  // OrderedSet out-of-scope, object should be deleted.
+
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseEnsureNotDeletionWhen(void)
+{
+  // Ensure that the object owned by the OrderedSET is deleted.
+
+  bool deleted = false;
+
+  OwnedClass* ptr;
+
+  {
+    // Create OrderedSet without ownership. It will not delete automatically.
+    OrderedSet<OwnedClass, false> set;
+    ptr = new OwnedClass(deleted);
+    set.PushBack(ptr);
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  }
+
+  // OrderedSet out-of-scope, but, object should not be deleted.
+
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  delete ptr;
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetDefaultConstructor(void)
+{
+  // Ensure the default constructor is created as expected.
+
+  OrderedSet<OwnedClass> set;
+  DALI_TEST_CHECK(set.Count() == 0u);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseDefaultConstructor(void)
+{
+  // Ensure the default constructor is created as expected.
+
+  OrderedSet<OwnedClass, false> set;
+  DALI_TEST_CHECK(set.Count() == 0u);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetReserve(void)
+{
+  OrderedSet<OwnedClass> set;
+  set.Reserve(100u);
+
+  // Reserve function didn't change the count.
+  DALI_TEST_CHECK(set.Count() == 0u);
+
+  OrderedSet<OwnedClass> set2;
+  set2.Reserve(100u);
+
+  // Reserve function didn't change the count.
+  DALI_TEST_CHECK(set2.Count() == 0u);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetMove(void)
+{
+  // Call move constructor and move assignment operator
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass> first;
+  DALI_TEST_CHECK(first.Find(owned) == first.End());
+  first.PushBack(owned);
+  DALI_TEST_CHECK(first.Find(owned) != first.End());
+
+  {
+    // Move constructor, first should have a nullptr now, no object deletion
+    OrderedSet<OwnedClass> second(std::move(first));
+    DALI_TEST_CHECK(first.Find(owned) == first.End());
+    DALI_TEST_CHECK(second.Find(owned) != second.End());
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+    // Assign second to first, no deletion, second should have a nullptr now
+    first = std::move(second);
+    DALI_TEST_CHECK(first.Find(owned) != first.End());
+    DALI_TEST_CHECK(second.Find(owned) == second.End());
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  }
+
+  // second is out-of-scope now, no object deletion
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  // Assign to an empty pointer, owned object should be deleted
+  OrderedSet<OwnedClass> empty;
+  first = std::move(empty);
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+  DALI_TEST_CHECK(first.Find(owned) == first.End());
+  DALI_TEST_CHECK(empty.Find(owned) == empty.End());
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseMove(void)
+{
+  // Call move constructor and move assignment operator
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass, false> first;
+  DALI_TEST_CHECK(first.Find(owned) == first.End());
+  first.PushBack(owned);
+  DALI_TEST_CHECK(first.Find(owned) != first.End());
+
+  {
+    // Move constructor, first should have a nullptr now, no object deletion
+    OrderedSet<OwnedClass, false> second(std::move(first));
+    DALI_TEST_CHECK(first.Find(owned) == first.End());
+    DALI_TEST_CHECK(second.Find(owned) != second.End());
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+    // Assign second to first, no deletion, second should have a nullptr now
+    first = std::move(second);
+    DALI_TEST_CHECK(first.Find(owned) != first.End());
+    DALI_TEST_CHECK(second.Find(owned) == second.End());
+    DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  }
+
+  // second is out-of-scope now, no object deletion
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  // Assign to an empty pointer, but owned object should not be deleted
+  OrderedSet<OwnedClass, false> empty;
+  first = std::move(empty);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  DALI_TEST_CHECK(first.Find(owned) == first.End());
+  DALI_TEST_CHECK(empty.Find(owned) == empty.End());
+
+  delete owned;
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetErase(void)
+{
+  // Ensure that calling Reset deletes the object and sets the owner-pointer to NULL
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass> set;
+  set.PushBack(owned);
+  DALI_TEST_EQUALS(set.Count(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  set.EraseObject(owned);
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseErase(void)
+{
+  // Ensure that calling Reset not deletes the object and sets the owner-pointer to NULL
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass, false> set;
+  set.PushBack(owned);
+  DALI_TEST_EQUALS(set.Count(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  set.EraseObject(owned);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  delete owned;
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetClear(void)
+{
+  // Ensure that calling Reset deletes the object and sets the owner-pointer to NULL
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass> set;
+  set.PushBack(owned);
+  DALI_TEST_EQUALS(set.Count(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  set.Clear();
+  DALI_TEST_EQUALS(set.Count(), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseClear(void)
+{
+  // Ensure that calling Reset deletes the object and sets the owner-pointer to NULL
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass, false> set;
+  set.PushBack(owned);
+  DALI_TEST_EQUALS(set.Count(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  set.Clear();
+  DALI_TEST_EQUALS(set.Count(), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  delete owned;
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetRelease(void)
+{
+  // Ensure that calling Release does NOT delete the object but still sets the owner-pointer to NULL
+
+  bool        deleted = false;
+  OwnedClass* owned   = new OwnedClass(deleted);
+
+  OrderedSet<OwnedClass> set;
+  set.PushBack(owned);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+
+  auto iter = set.Find(owned);
+  DALI_TEST_CHECK(iter != set.End());
+  DALI_TEST_EQUALS(set.Count(), 1u, TEST_LOCATION);
+
+  OwnedClass* released = set.Release(iter);
+  DALI_TEST_EQUALS(deleted, false, TEST_LOCATION);
+  DALI_TEST_CHECK(set.Find(owned) == set.End());
+  DALI_TEST_CHECK(set.Find(released) == set.End());
+  DALI_TEST_EQUALS(set.Count(), 0u, TEST_LOCATION);
+
+  delete released;
+  DALI_TEST_EQUALS(deleted, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetIteratorOrderCheck(void)
+{
+  // Ensure that order of iterator is equal with Order of Insertion.
+
+  // Reset refcount of class
+  ClassWithId::gRefCount = 0;
+
+  // To avoid lucky pass, run this test multiple time.
+  int tryCnt = 3;
+  while(tryCnt--)
+  {
+    int baseId = tryCnt; // random id
+    int id     = baseId;
+    int n      = 10 + 5 * (tryCnt + 1); // random count
+
+    OrderedSet<ClassWithId> set;
+
+    for(int i = 0; i < n; ++i)
+    {
+      ClassWithId* object = new ClassWithId(id++);
+      set.PushBack(object);
+    }
+
+    int expectId;
+    // Check by for iteration
+    expectId = baseId;
+    for(auto iter = set.Begin(), iterEnd = set.End(); iter != iterEnd; ++iter)
+    {
+      DALI_TEST_EQUALS(expectId++, (*iter)->mId, TEST_LOCATION);
+    }
+    DALI_TEST_EQUALS(expectId, id, TEST_LOCATION);
+
+    // Check by range referenced iteration
+    expectId = baseId;
+    for(auto&& iter : set)
+    {
+      DALI_TEST_EQUALS(expectId++, iter->mId, TEST_LOCATION);
+      // Change iter's value.
+      ++(iter->mId);
+    }
+    DALI_TEST_EQUALS(expectId, id, TEST_LOCATION);
+
+    // Check by range iteration. Note that class value changed.
+    expectId = baseId + 1;
+    for(const auto& iter : set)
+    {
+      DALI_TEST_EQUALS(expectId++, iter->mId, TEST_LOCATION);
+    }
+    DALI_TEST_EQUALS(expectId, id + 1, TEST_LOCATION);
+  }
+
+  // Check whether leak exist.
+  DALI_TEST_EQUALS(ClassWithId::gRefCount, 0, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliOrderedSetFalseIteratorOrderCheck(void)
+{
+  // Ensure that order of iterator is equal with Order of Insertion.
+
+  // Reset refcount of class
+  ClassWithId::gRefCount = 0;
+
+  // Container of ownered class, to release memories after test finished.
+  std::vector<ClassWithId*> objectList;
+
+  // To avoid lucky pass, run this test multiple time.
+  int tryCnt = 3;
+  while(tryCnt--)
+  {
+    int baseId = tryCnt; // random id
+    int id     = baseId;
+    int n      = 10 + 5 * (tryCnt + 1); // random count
+
+    OrderedSet<ClassWithId, false> set;
+
+    for(int i = 0; i < n; ++i)
+    {
+      ClassWithId* object = new ClassWithId(id++);
+      objectList.push_back(object);
+      set.PushBack(object);
+    }
+
+    int expectId;
+    // Check by for iteration
+    expectId = baseId;
+    for(auto iter = set.Begin(), iterEnd = set.End(); iter != iterEnd; ++iter)
+    {
+      DALI_TEST_EQUALS(expectId++, (*iter)->mId, TEST_LOCATION);
+    }
+    DALI_TEST_EQUALS(expectId, id, TEST_LOCATION);
+
+    // Check by range referenced iteration
+    expectId = baseId;
+    for(auto&& iter : set)
+    {
+      DALI_TEST_EQUALS(expectId++, iter->mId, TEST_LOCATION);
+      // Change iter's value.
+      ++(iter->mId);
+    }
+    DALI_TEST_EQUALS(expectId, id, TEST_LOCATION);
+
+    // Check by range iteration. Note that class value changed.
+    expectId = baseId + 1;
+    for(const auto& iter : set)
+    {
+      DALI_TEST_EQUALS(expectId++, iter->mId, TEST_LOCATION);
+    }
+    DALI_TEST_EQUALS(expectId, id + 1, TEST_LOCATION);
+  }
+
+  // Check whether leak exist.
+  DALI_TEST_EQUALS(ClassWithId::gRefCount, objectList.size(), TEST_LOCATION);
+
+  // Release memory now.
+  for(auto&& iter : objectList)
+  {
+    delete iter;
+  }
+  objectList.clear();
+  DALI_TEST_EQUALS(ClassWithId::gRefCount, 0, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/dali/internal/common/ordered-set.h b/dali/internal/common/ordered-set.h
new file mode 100644 (file)
index 0000000..9f86dae
--- /dev/null
@@ -0,0 +1,322 @@
+#ifndef DALI_INTERNAL_ORDERED_SET_H
+#define DALI_INTERNAL_ORDERED_SET_H
+
+/*
+ * Copyright (c) 2023 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 <unordered_map>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/list-wrapper.h>
+
+namespace Dali
+{
+namespace Internal
+{
+/**
+ * @brief Container of data which has strong point to Find & Erase.
+ * It will be useful when we need to iterate the order of data insertion.
+ * and need to check whether some object is exist or not very fast.
+ * @note Since the data's memory is not continuos, iteration is slower than normal vector contianer.
+ *
+ * @tparam T The type of class
+ * @tparam owned True if data is owned, So we will automatcally release the memory
+ *               False if data is not owned by this set. Default as true.
+ * @tparam Hash Custom hash function of const T* type for MapContainer.
+ *              Note that if two const T* return true at KeyEqual, Hash should return same value.
+ *              Default as std::hash<const T*>
+ * @tparam KeyEqual Custom equal function of const T* type for MapContainer.
+ *                  Return true if two const T* type is equal. Default as std::equal_to<const T*>
+ */
+template<class T, bool owned = true, class Hash = std::hash<const T*>, class KeyEqual = std::equal_to<const T*>>
+class OrderedSet
+{
+public:
+  // Real data owned container.
+  using ListContainer = typename std::list<T*>;
+  using Iterator      = typename ListContainer::iterator;
+  using ConstIterator = typename ListContainer::const_iterator;
+
+  // Find helper map container.
+  using MapContainer = typename std::unordered_map<const T*, Iterator, Hash, KeyEqual>;
+
+  using SizeType = std::size_t;
+
+  /**
+   * @brief Construct a new OrderedSet object
+   */
+  OrderedSet() = default;
+
+  /**
+   * @brief Move construct
+   */
+  OrderedSet(OrderedSet&& rhs)
+  : mMap(std::move(rhs.mMap)),
+    mList(std::move(rhs.mList))
+  {
+    rhs.mMap.clear();
+    rhs.mMap.rehash(0);
+    rhs.mList.clear();
+  }
+
+  /**
+   * @brief Move assign
+   */
+  OrderedSet& operator=(OrderedSet&& rhs)
+  {
+    Clear();
+    mMap  = std::move(rhs.mMap);
+    mList = std::move(rhs.mList);
+    rhs.mMap.clear();
+    rhs.mMap.rehash(0);
+    rhs.mList.clear();
+    return *this;
+  }
+
+  ~OrderedSet()
+  {
+    Clear();
+  }
+
+  /**
+   * @brief Iterator of begin & end
+   */
+  Iterator Begin()
+  {
+    return mList.begin();
+  }
+  Iterator End()
+  {
+    return mList.end();
+  }
+  ConstIterator Begin() const
+  {
+    return mList.begin();
+  }
+  ConstIterator End() const
+  {
+    return mList.end();
+  }
+
+  // Support for C++11 Range-based for loop: for( item : container ).
+  Iterator begin()
+  {
+    return Begin();
+  }
+  Iterator end()
+  {
+    return End();
+  }
+  ConstIterator begin() const
+  {
+    return Begin();
+  }
+  ConstIterator end() const
+  {
+    return End();
+  }
+
+  /**
+   * @brief Get the number of elements.
+   *
+   * @return The number of elements that this container owned.
+   */
+  SizeType Count() const
+  {
+    return mMap.size();
+  }
+
+  /**
+   * @brief Reserves space in the ordered set.
+   *
+   * @param[in] count Count of elements to reserve
+   */
+  void Reserve(SizeType count)
+  {
+    if(mMap.size() < count)
+    {
+      mMap.rehash(count);
+    }
+  }
+
+  /**
+   * @brief Find and get iterator of object. If not exist, return End().
+   *
+   * @param[in] object The object pointer what we want to find.
+   * @return Iterator of object, or End().
+   */
+  Iterator Find(T* object)
+  {
+    auto mapIter = mMap.find(object);
+    if(mapIter == mMap.end())
+    {
+      return End();
+    }
+    return mapIter->second;
+  }
+  ConstIterator Find(const T* object) const
+  {
+    auto mapIter = mMap.find(object);
+    if(mapIter == mMap.end())
+    {
+      return End();
+    }
+    return mapIter->second;
+  }
+
+  /**
+   * @brief PushBack and keep ownership of object.
+   * @note Iterator will keep order of PushBack API call.
+   *
+   * @param[in] object The object pointer what we want to insert.
+   */
+  void PushBack(T* object)
+  {
+    DALI_ASSERT_DEBUG(Find(object) == End());
+    auto newIter = mList.insert(mList.end(), object);
+    mMap.insert({object, newIter});
+  }
+
+  /**
+   * @brief Erase and remove memory of object.
+   *
+   * @param[in] object The object pointer what we want to erase.
+   */
+  void EraseObject(T* object)
+  {
+    // TODO : Should we allow duplicated erase?
+    //DALI_ASSERT_DEBUG(Find(object) != End());
+    Erase(Find(object));
+  }
+  void EraseObject(const T* object)
+  {
+    // TODO : Should we allow duplicated erase?
+    //DALI_ASSERT_DEBUG(Find(object) != End());
+    Erase(Find(object));
+  }
+
+  /**
+   * @brief Erase and remove memory of object by iterator.
+   *
+   * @param[in] iter The iterator what we want to erase.
+   */
+  Iterator Erase(Iterator iter)
+  {
+    Iterator ret = mList.end();
+    if(iter != mList.end())
+    {
+      // Erase mMap first.
+      auto mapIter = mMap.find(*iter);
+      DALI_ASSERT_DEBUG(mapIter != mMap.end());
+      mMap.erase(mapIter);
+
+      // Erase owned object.
+      if constexpr(owned)
+      {
+        delete *iter;
+      }
+      ret = mList.erase(iter);
+    }
+    return ret;
+  }
+  ConstIterator Erase(ConstIterator iter)
+  {
+    ConstIterator ret = mList.end();
+    if(iter != mList.end())
+    {
+      // Erase mMap first.
+      auto mapIter = mMap.find(*iter);
+      DALI_ASSERT_DEBUG(mapIter != mMap.end());
+      mMap.erase(mapIter);
+
+      // Erase owned object.
+      if constexpr(owned)
+      {
+        delete *iter;
+      }
+      ret = mList.erase(iter);
+    }
+    return ret;
+  }
+
+  /**
+   * @brief Release and move ownership of object.
+   * This API do not remove memory.
+   *
+   * @param[in] iter The iterator what we want to release.
+   */
+  T* Release(Iterator iter)
+  {
+    T* result = (*iter);
+
+    // Erase mMap first.
+    auto mapIter = mMap.find(result);
+    DALI_ASSERT_DEBUG(mapIter != mMap.end());
+    mMap.erase(mapIter);
+
+    // Erase without delete reference
+    mList.erase(iter);
+    return result;
+  }
+  T* Release(ConstIterator iter)
+  {
+    const T* result = (*iter);
+
+    // Erase mMap first.
+    auto mapIter = mMap.find(result);
+    DALI_ASSERT_DEBUG(mapIter != mMap.end());
+    mMap.erase(mapIter);
+
+    // Erase without delete reference
+    mList.erase(iter);
+    return result;
+  }
+
+  /**
+   * @brief Remove all data and release memory if we owned data.
+   */
+  void Clear()
+  {
+    // Delete memory
+    if constexpr(owned)
+    {
+      for(auto&& iter : mList)
+      {
+        delete iter;
+      }
+    }
+    mMap.clear();
+    mMap.rehash(0);
+    mList.clear();
+  }
+
+private:
+  // Delete copy operation.
+  OrderedSet(const OrderedSet&) = delete;
+  OrderedSet& operator=(const OrderedSet&) = delete;
+
+private:
+  MapContainer  mMap{};  ///< Helper cache map to find item fast.
+  ListContainer mList{}; ///< Ordered by PushBack API called. Actual ownership will be stored here.
+};
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ORDERED_SET_H
index 17e47ff..a2edbd1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -43,26 +43,40 @@ void AnimationPlaylist::AnimationCreated(Animation& animation)
 
 void AnimationPlaylist::AnimationDestroyed(Animation& animation)
 {
-  Dali::Vector<Animation*>::Iterator iter = std::find(mAnimations.Begin(), mAnimations.End(), &animation);
+  auto iter = mAnimations.Find(&animation);
   DALI_ASSERT_ALWAYS(iter != mAnimations.End() && "Animation not found");
 
-  mAnimations.Remove(iter);
+  mAnimations.Erase(iter);
 }
 
 void AnimationPlaylist::OnPlay(Animation& animation)
 {
-  mPlaylist.push_back(Dali::Animation(&animation));
+  Dali::Animation handle = Dali::Animation(&animation);
+  auto            iter   = mPlaylist.lower_bound(handle);
+  if(iter != mPlaylist.end() && (*iter).first == handle)
+  {
+    // Just increase reference count.
+    ++(iter->second);
+  }
+  else
+  {
+    mPlaylist.insert(iter, {handle, 1u});
+  }
 }
 
 void AnimationPlaylist::OnClear(Animation& animation)
 {
-  std::vector<Dali::Animation>::iterator iter = std::find(mPlaylist.begin(), mPlaylist.end(), Dali::Animation(&animation));
-  std::vector<Dali::Animation>::iterator last = mPlaylist.end();
-  if(iter != last)
+  Dali::Animation handle = Dali::Animation(&animation);
+  auto            iter   = mPlaylist.find(handle);
+
+  // Animation might be removed when NotifyCompleted called.
+  if(DALI_LIKELY(iter != mPlaylist.end()))
   {
-    --last;                  // move to real last
-    std::swap(*iter, *last); // swap
-    mPlaylist.resize(mPlaylist.size() - 1u);
+    // Just decrease reference count. But if reference count is zero, remove it.
+    if(--(iter->second) == 0u)
+    {
+      mPlaylist.erase(iter);
+    }
   }
 }
 
@@ -72,24 +86,21 @@ void AnimationPlaylist::NotifyCompleted()
 
   // Since animations can be unreferenced during the signal emissions, iterators into animationPointers may be invalidated.
   // First copy and reference the finished animations, then emit signals
-  for(Dali::Vector<Animation*>::Iterator iter = mAnimations.Begin(); iter != mAnimations.End(); ++iter)
+  for(auto* animation : mAnimations)
   {
-    Animation* animation = *iter;
-
     if(animation->HasFinished())
     {
-      finishedAnimations.push_back(Dali::Animation(animation));
+      Dali::Animation handle = Dali::Animation(animation);
+      finishedAnimations.push_back(handle);
 
       // The animation may be present in mPlaylist - remove if necessary
       // Note that the animation "Finish" signal is emitted after Stop() has been called
-      std::vector<Dali::Animation>::iterator iter = std::find(mPlaylist.begin(), mPlaylist.end(), Dali::Animation(animation));
-      DALI_ASSERT_DEBUG(iter != mPlaylist.end());
-      mPlaylist.erase(iter);
+      OnClear(*animation);
     }
   }
 
   // Now it's safe to emit the signals
-  for(std::vector<Dali::Animation>::iterator iter = finishedAnimations.begin(); iter != finishedAnimations.end(); ++iter)
+  for(auto iter = finishedAnimations.begin(); iter != finishedAnimations.end(); ++iter)
   {
     Dali::Animation& handle = *iter;
 
@@ -101,10 +112,8 @@ void AnimationPlaylist::NotifyProgressReached(const SceneGraph::Animation* scene
 {
   std::vector<Dali::Animation> notifyProgressAnimations; // Will own animations until all emits have been done
 
-  for(Dali::Vector<Animation*>::Iterator iter = mAnimations.Begin(); iter != mAnimations.End(); ++iter)
+  for(auto* animation : mAnimations)
   {
-    Animation* animation = *iter;
-
     if((animation->GetSceneObject()) == sceneGraphAnimation)
     {
       // Store handles to animations that need signals emitted in the case of an animation being cleared in-between emits
@@ -122,17 +131,30 @@ void AnimationPlaylist::NotifyProgressReached(const SceneGraph::Animation* scene
 
 uint32_t AnimationPlaylist::GetAnimationCount()
 {
-  return mAnimations.Size();
+  return mAnimations.Count();
 }
 
 Dali::Animation AnimationPlaylist::GetAnimationAt(uint32_t index)
 {
-  if(index >= mAnimations.Size())
+  if(index >= mAnimations.Count())
   {
     DALI_LOG_ERROR("Animation index is out of bounds.\n");
     return Dali::Animation();
   }
-  return Dali::Animation(mAnimations[index]);
+
+  // This will spend a lot of time. But GetAnimationAt API will be called very rarely.
+  Animation* ret = nullptr;
+  for(auto iter : mAnimations)
+  {
+    if(index == 0u)
+    {
+      ret = iter;
+      break;
+    }
+    --index;
+  }
+  DALI_ASSERT_DEBUG(ret != nullptr);
+  return Dali::Animation(ret);
 }
 
 } // namespace Internal
index ad3e3d7..5b0a8b4 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ANIMATION_PLAYLIST_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -19,7 +19,9 @@
  */
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
 #include <dali/internal/common/message.h>
+#include <dali/internal/common/ordered-set.h>
 #include <dali/internal/event/common/complete-notification-interface.h>
 #include <dali/public-api/animation/animation.h>
 #include <dali/public-api/common/dali-vector.h>
@@ -116,8 +118,8 @@ private: // from CompleteNotificationInterface
   void NotifyCompleted() override;
 
 private:
-  Dali::Vector<Animation*>     mAnimations; ///< All existing animations (not owned)
-  std::vector<Dali::Animation> mPlaylist;   ///< The currently playing animations (owned through handle)
+  OrderedSet<Animation, false>        mAnimations; ///< All existing animations (not owned)
+  std::map<Dali::Animation, uint32_t> mPlaylist;   ///< The currently playing animations (owned through handle). Note we can hold same handles multiple.
 };
 
 /**
index 6ffecf2..2585bae 100644 (file)
@@ -219,6 +219,9 @@ void PropertyNotification::CreateSceneObject()
                                                                   mCompare);
     OwnerPointer<SceneGraph::PropertyNotification> transferOwnership(const_cast<SceneGraph::PropertyNotification*>(mPropertyNotification));
     AddPropertyNotificationMessage(mUpdateManager, transferOwnership);
+
+    // Setup mapping infomations between scenegraph property notification
+    mPropertyNotificationManager.PropertyNotificationSceneObjectMapping(mPropertyNotification, *this);
   }
 }
 
@@ -228,6 +231,9 @@ void PropertyNotification::DestroySceneObject()
   {
     DALI_ASSERT_ALWAYS(EventThreadServices::IsCoreRunning());
 
+    // Remove mapping infomations
+    mPropertyNotificationManager.PropertyNotificationSceneObjectUnmapping(mPropertyNotification);
+
     // Remove PropertyNotification using a message to the update manager
     RemovePropertyNotificationMessage(mUpdateManager, *mPropertyNotification);
     mPropertyNotification = nullptr;
index f150167..873e940 100644 (file)
@@ -40,28 +40,38 @@ void PropertyNotificationManager::PropertyNotificationCreated(PropertyNotificati
 
 void PropertyNotificationManager::PropertyNotificationDestroyed(PropertyNotification& propertyNotification)
 {
-  Dali::Vector<PropertyNotification*>::Iterator iter = std::find(mPropertyNotifications.Begin(), mPropertyNotifications.End(), &propertyNotification);
+  auto iter = mPropertyNotifications.Find(&propertyNotification);
   DALI_ASSERT_ALWAYS(iter != mPropertyNotifications.End() && "PropertyNotification not found");
 
-  mPropertyNotifications.Remove(iter);
+  mPropertyNotifications.Erase(iter);
 }
 
-void PropertyNotificationManager::NotifyProperty(SceneGraph::PropertyNotification* propertyNotification, bool validity)
+void PropertyNotificationManager::PropertyNotificationSceneObjectMapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification, PropertyNotification& propertyNotification)
 {
-  Dali::Vector<PropertyNotification*>::Iterator       iter    = mPropertyNotifications.Begin();
-  const Dali::Vector<PropertyNotification*>::Iterator endIter = mPropertyNotifications.End();
+  mSceneGraphObjectMap.insert({sceneGraphPropertyNotification, &propertyNotification});
+}
+
+void PropertyNotificationManager::PropertyNotificationSceneObjectUnmapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification)
+{
+  auto iter = mSceneGraphObjectMap.find(sceneGraphPropertyNotification);
+  DALI_ASSERT_DEBUG(iter != mSceneGraphObjectMap.end());
 
-  // walk the collection of PropertyNotifications
-  for(; iter != endIter; ++iter)
+  mSceneGraphObjectMap.erase(iter);
+}
+
+void PropertyNotificationManager::NotifyProperty(SceneGraph::PropertyNotification* sceneGraphPropertyNotification, bool validity)
+{
+  const auto iter = mSceneGraphObjectMap.find(sceneGraphPropertyNotification);
+  if(iter != mSceneGraphObjectMap.end())
   {
-    // found one with the matching SceneGraph::PropertyNotification?
-    if((*iter)->CompareSceneObject(propertyNotification))
+    // Check if this notification hold inputed scenegraph property notification.
+    auto* propertyNotification = iter->second;
+    if(propertyNotification->CompareSceneObject(sceneGraphPropertyNotification))
     {
       // allow application to access the value that triggered this emit incase of NOTIFY_ON_CHANGED mode
-      (*iter)->SetNotifyResult(validity);
+      propertyNotification->SetNotifyResult(validity);
       // yes..emit signal
-      (*iter)->EmitSignalNotify();
-      break;
+      propertyNotification->EmitSignalNotify();
     }
   }
 }
index 77128dd..4229be2 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_PROPERTY_NOTIFICATION_MANAGER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
+// EXTERNAL INCLUDES
+#include <unordered_map>
+
 // INTERNAL INCLUDES
+#include <dali/internal/common/ordered-set.h>
 #include <dali/internal/event/common/property-notifier.h>
 #include <dali/public-api/common/dali-vector.h>
 
@@ -58,11 +62,21 @@ public:
    */
   void PropertyNotificationDestroyed(PropertyNotification& propertyNotification);
 
+  /**
+   * Called when a SceneGraph::PropertyNotification is mapping by PropertyNotification.
+   */
+  void PropertyNotificationSceneObjectMapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification, PropertyNotification& propertyNotification);
+
+  /**
+   * Called when a SceneGraph::PropertyNotification is unmaped from PropertyNotification.
+   */
+  void PropertyNotificationSceneObjectUnmapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification);
+
 private: // private virtual overrides
   /**
    * @copydoc PropertyNotifier::NotifyProperty
    */
-  void NotifyProperty(SceneGraph::PropertyNotification* propertyNotification, bool validity) override;
+  void NotifyProperty(SceneGraph::PropertyNotification* sceneGraphPropertyNotification, bool validity) override;
 
 private:
   /**
@@ -77,7 +91,9 @@ private:
   PropertyNotificationManager& operator=(const PropertyNotificationManager& rhs);
 
 private:
-  Dali::Vector<PropertyNotification*> mPropertyNotifications; ///< All existing PropertyNotifications (not owned)
+  OrderedSet<PropertyNotification, false> mPropertyNotifications; ///< All existing PropertyNotifications (not owned)
+
+  std::unordered_map<const SceneGraph::PropertyNotification*, PropertyNotification*> mSceneGraphObjectMap; ///< Converter from SceneGraph object pointer to Event object.
 };
 
 } // namespace Internal
index 2554e14..901d5b1 100644 (file)
@@ -25,23 +25,22 @@ namespace Internal
 MemoryPoolRelayoutContainer::MemoryPoolRelayoutContainer(MemoryPoolObjectAllocator<RelayoutInfo>& objectAllocator)
 : mAllocator(objectAllocator)
 {
+  mDummyRelayoutInfo.reset(new RelayoutInfo());
 }
 
 MemoryPoolRelayoutContainer::~MemoryPoolRelayoutContainer() = default;
 
 bool MemoryPoolRelayoutContainer::Contains(const Dali::Actor& actor)
 {
-  for(RelayoutInfoContainer::Iterator it = mRelayoutInfos.Begin(), itEnd = mRelayoutInfos.End(); it != itEnd; ++it)
-  {
-    RelayoutInfo* info = *it;
+  // Store actor into dummy info.
+  // It will be used for check comparision.
+  mDummyRelayoutInfo->actor = actor;
 
-    if(info->actor == actor)
-    {
-      return true;
-    }
-  }
+  bool ret = (mRelayoutInfos.Find(mDummyRelayoutInfo.get()) != mRelayoutInfos.End());
 
-  return false;
+  // Reset empty handle for deference.
+  mDummyRelayoutInfo->actor = Dali::Actor();
+  return ret;
 }
 
 void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& size)
@@ -59,28 +58,33 @@ void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& s
 
 void MemoryPoolRelayoutContainer::PopBack()
 {
-  if(mRelayoutInfos.Size() > 0)
+  if(mRelayoutInfos.Count() > 0)
   {
     RelayoutInfoContainer::Iterator back = mRelayoutInfos.End();
     back--;
     RelayoutInfo* info = *back;
-    mAllocator.Destroy(info);
     mRelayoutInfos.Erase(back);
+
+    // Need to be destroyed after mRelayoutInfos erased.
+    mAllocator.Destroy(info);
   }
 }
 
-void MemoryPoolRelayoutContainer::Get(size_t index, Dali::Actor& actorOut, Vector2& sizeOut) const
+void MemoryPoolRelayoutContainer::GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const
 {
-  DALI_ASSERT_DEBUG(index < Size());
-
-  RelayoutInfo* info = mRelayoutInfos[index];
-  actorOut           = info->actor;
-  sizeOut            = info->size;
+  if(mRelayoutInfos.Count() > 0)
+  {
+    RelayoutInfoContainer::ConstIterator back = mRelayoutInfos.End();
+    back--;
+    RelayoutInfo* info = *back;
+    actorOut           = info->actor;
+    sizeOut            = info->size;
+  }
 }
 
 size_t MemoryPoolRelayoutContainer::Size() const
 {
-  return mRelayoutInfos.Size();
+  return mRelayoutInfos.Count();
 }
 
 void MemoryPoolRelayoutContainer::Reserve(size_t capacity)
@@ -90,9 +94,8 @@ void MemoryPoolRelayoutContainer::Reserve(size_t capacity)
 
 void MemoryPoolRelayoutContainer::Clear()
 {
-  for(size_t i = 0; i < Size(); ++i)
+  for(auto& info : mRelayoutInfos)
   {
-    RelayoutInfo* info = mRelayoutInfos[i];
     mAllocator.Destroy(info);
   }
 
index 4a143c7..87e7176 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_MEMORY_POOL_RELAYOUT_CONTAINER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
+// EXTERNAL INCLUDES
+#include <memory> // for std::unique_ptr
+
 // INTERNAL INCLUDES
 #include <dali/public-api/actors/actor.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
 
 #include <dali/internal/common/memory-pool-object-allocator.h>
+#include <dali/internal/common/ordered-set.h>
 
 namespace Dali
 {
@@ -44,6 +48,20 @@ public:
   {
     Dali::Actor actor; ///< The actor to relayout
     Vector2     size;  ///< The desired size of the actor
+    struct RelayoutInfoHash
+    {
+      std::size_t operator()(const RelayoutInfo* x) const noexcept
+      {
+        return reinterpret_cast<std::size_t>(x->actor.GetObjectPtr());
+      }
+    };
+    struct RelayoutInfoCompare
+    {
+      bool operator()(const RelayoutInfo* lhs, const RelayoutInfo* rhs) const noexcept
+      {
+        return lhs->actor == rhs->actor;
+      }
+    };
   };
 
   /**
@@ -72,11 +90,12 @@ public:
   void PopBack();
 
   /**
-   * @brief Retrieve relayout information for the given index
+   * @brief Retrieve relayout information for the latest added
    *
-   * @param index The index of the information to retrieve
+   * @param[out] actorOut Latest added actor
+   * @param[out] sizeOt Latest added size
    */
-  void Get(size_t index, Dali::Actor& actorOut, Vector2& sizeOut) const;
+  void GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const;
 
   /**
    * @brief The count of information in the container
@@ -95,6 +114,7 @@ public:
    */
   void Clear();
 
+private:
   /**
    * @brief Returns if the container contains the actor or not
    *
@@ -104,11 +124,13 @@ public:
   bool Contains(const Dali::Actor& actor);
 
 private:
-  using RelayoutInfoContainer = Vector<RelayoutInfo*>;
+  using RelayoutInfoContainer = Dali::Internal::OrderedSet<RelayoutInfo, false, RelayoutInfo::RelayoutInfoHash, RelayoutInfo::RelayoutInfoCompare>;
 
   RelayoutInfoContainer mRelayoutInfos; ///< The list of relayout infos
 
   MemoryPoolObjectAllocator<RelayoutInfo>& mAllocator; ///< The memory pool from which the infos are allocated
+
+  std::unique_ptr<RelayoutInfo> mDummyRelayoutInfo; ///< Dummy pointer that will be used to compare relayout infors what we already holded.
 };
 
 } // namespace Internal
index c32cebe..93585f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -121,10 +121,7 @@ RelayoutController::RelayoutController(Integration::RenderController& controller
   mRelayoutStack->Reserve(32);
 }
 
-RelayoutController::~RelayoutController()
-{
-  delete mRelayoutStack;
-}
+RelayoutController::~RelayoutController() = default;
 
 RelayoutController* RelayoutController::Get()
 {
@@ -372,9 +369,9 @@ void RelayoutController::AddRequest(Dali::Actor& actor)
   Internal::Actor* actorPtr = &GetImplementation(actor);
 
   // Only add the rootActor if it is not already recorded
-  auto itr = std::find(mDirtyLayoutSubTrees.begin(), mDirtyLayoutSubTrees.end(), actorPtr);
+  auto iter = mDirtyLayoutSubTrees.Find(actorPtr);
 
-  if(itr == mDirtyLayoutSubTrees.end())
+  if(iter == mDirtyLayoutSubTrees.End())
   {
     mDirtyLayoutSubTrees.PushBack(actorPtr);
   }
@@ -383,11 +380,7 @@ void RelayoutController::AddRequest(Dali::Actor& actor)
 void RelayoutController::RemoveRequest(Dali::Actor& actor)
 {
   Internal::Actor* actorPtr = &GetImplementation(actor);
-
-  mDirtyLayoutSubTrees.Erase(std::remove(mDirtyLayoutSubTrees.begin(),
-                                         mDirtyLayoutSubTrees.end(),
-                                         actorPtr),
-                             mDirtyLayoutSubTrees.end());
+  mDirtyLayoutSubTrees.EraseObject(actorPtr);
 }
 
 void RelayoutController::Request()
@@ -404,8 +397,7 @@ void RelayoutController::Request()
 
 void RelayoutController::OnObjectDestroyed(const Dali::RefObject* object)
 {
-  // Search for and null the object if found in the following lists
-  FindAndZero(mDirtyLayoutSubTrees, object);
+  mDirtyLayoutSubTrees.EraseObject(static_cast<const Dali::Internal::Actor*>(object));
 }
 
 void RelayoutController::Relayout()
@@ -446,7 +438,8 @@ void RelayoutController::Relayout()
       {
         Dali::Actor actor;
         Vector2     size;
-        mRelayoutStack->Get(mRelayoutStack->Size() - 1, actor, size);
+
+        mRelayoutStack->GetBack(actor, size);
         Actor& actorImpl = GetImplementation(actor);
         mRelayoutStack->PopBack();
 
@@ -487,18 +480,6 @@ void RelayoutController::SetProcessingCoreEvents(bool processingEvents)
   mProcessingCoreEvents = processingEvents;
 }
 
-void RelayoutController::FindAndZero(const RawActorList& list, const Dali::RefObject* object)
-{
-  // Object has been destroyed so clear it from this list
-  for(auto& actor : list)
-  {
-    if(actor && (actor == object))
-    {
-      actor = nullptr; // Reset the pointer in the list. We don't want to remove it in case something is iterating over the list.
-    }
-  }
-}
-
 uint32_t RelayoutController::GetMemoryPoolCapacity()
 {
   return mRelayoutInfoAllocator.GetCapacity();
index 29809ea..e524406 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RELAYOUT_CONTROLLER_IMPL_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 // EXTERNAL INCLUDES
 #include <cstdint>
+#include <memory> // for unique_ptr
 
 // INTERNAL INCLUDES
 #include <dali/internal/common/memory-pool-object-allocator.h>
+#include <dali/internal/common/ordered-set.h>
 #include <dali/internal/event/size-negotiation/memory-pool-relayout-container.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/object/base-object.h>
@@ -144,7 +146,7 @@ public: // CALLBACKS
   void OnObjectDestroyed(const Dali::RefObject* object);
 
 private:
-  using RawActorList = Dali::Vector<Dali::Internal::Actor*>;
+  using RawActorList = Dali::Internal::OrderedSet<Dali::Internal::Actor, false>;
 
   /**
    * @brief Request for relayout. Relays out whole scene.
@@ -190,14 +192,6 @@ private:
    */
   void QueueActor(Internal::Actor* actor, RelayoutContainer& actors, Vector2 size);
 
-  /**
-   * @brief Find the given object in the list and null it out
-   *
-   * @param[in] list The list to search
-   * @param[in] object The object to search for
-   */
-  void FindAndZero(const RawActorList& list, const Dali::RefObject* object);
-
   // Undefined
   RelayoutController(const RelayoutController&) = delete;
   RelayoutController& operator=(const RelayoutController&) = delete;
@@ -208,8 +202,9 @@ private:
 
   SlotDelegate<RelayoutController> mSlotDelegate;
 
-  RawActorList                 mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty
-  MemoryPoolRelayoutContainer* mRelayoutStack;       ///< Stack for relayouting
+  RawActorList mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty
+
+  std::unique_ptr<MemoryPoolRelayoutContainer> mRelayoutStack; ///< Stack for relayouting
 
   bool mRelayoutConnection : 1;   ///< Whether EventProcessingFinishedSignal signal is connected.
   bool mRelayoutFlag : 1;         ///< Relayout flag to avoid unnecessary calls
index 4464e83..e54741f 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali/devel-api/threading/thread-pool.h>
 #include <dali/integration-api/core.h>
+#include <dali/internal/common/ordered-set.h>
 
 #include <dali/internal/event/common/scene-impl.h>
 
@@ -154,13 +155,14 @@ struct RenderManager::Impl
   std::vector<SceneGraph::Scene*> sceneContainer;   ///< List of pointers to the scene graph objects of the scenes
   Render::RenderAlgorithms        renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction
 
-  OwnerContainer<Render::Sampler*>       samplerContainer;      ///< List of owned samplers
-  OwnerContainer<Render::FrameBuffer*>   frameBufferContainer;  ///< List of owned framebuffers
-  OwnerContainer<Render::VertexBuffer*>  vertexBufferContainer; ///< List of owned vertex buffers
-  OwnerContainer<Render::Geometry*>      geometryContainer;     ///< List of owned Geometries
-  OwnerContainer<Render::RenderTracker*> mRenderTrackers;       ///< List of render trackers
-  OwnerKeyContainer<Render::Renderer>    rendererContainer;     ///< List of owned renderers
-  OwnerKeyContainer<Render::Texture>     textureContainer;      ///< List of owned textures
+  OrderedSet<Render::Sampler>         samplerContainer;      ///< List of owned samplers
+  OrderedSet<Render::FrameBuffer>     frameBufferContainer;  ///< List of owned framebuffers
+  OrderedSet<Render::VertexBuffer>    vertexBufferContainer; ///< List of owned vertex buffers
+  OrderedSet<Render::Geometry>        geometryContainer;     ///< List of owned Geometries
+  OwnerKeyContainer<Render::Renderer> rendererContainer;     ///< List of owned renderers
+  OwnerKeyContainer<Render::Texture>  textureContainer;      ///< List of owned textures
+
+  OrderedSet<Render::RenderTracker> mRenderTrackers; ///< List of owned render trackers
 
   ProgramController   programController; ///< Owner of the programs
   Render::ShaderCache shaderCache;       ///< The cache for the graphics shaders
@@ -251,10 +253,10 @@ void RenderManager::RemoveTexture(const Render::TextureKey& textureKey)
 {
   DALI_ASSERT_DEBUG(textureKey && "Trying to remove empty texture key");
 
-  // Find the texture, use std::find so we can do the erase safely
-  auto iter = std::find(mImpl->textureContainer.begin(), mImpl->textureContainer.end(), textureKey);
+  // Find the texture, use std::find so we can do the erase by iterator safely
+  auto iter = std::find(mImpl->textureContainer.Begin(), mImpl->textureContainer.End(), textureKey);
 
-  if(iter != mImpl->textureContainer.end())
+  if(iter != mImpl->textureContainer.End())
   {
     textureKey->Destroy();
     mImpl->textureContainer.Erase(iter); // Texture found; now destroy it
@@ -297,10 +299,10 @@ void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer)
 {
   DALI_ASSERT_DEBUG(nullptr != frameBuffer);
 
-  // Find the framebuffer, use std:find so we can safely do the erase
-  auto iter = std::find(mImpl->frameBufferContainer.begin(), mImpl->frameBufferContainer.end(), frameBuffer);
+  // Find the framebuffer, use OrderedSet.Find so we can safely do the erase
+  auto iter = mImpl->frameBufferContainer.Find(frameBuffer);
 
-  if(iter != mImpl->frameBufferContainer.end())
+  if(iter != mImpl->frameBufferContainer.End())
   {
     frameBuffer->Destroy();
     mImpl->frameBufferContainer.Erase(iter); // frameBuffer found; now destroy it
@@ -379,42 +381,17 @@ void RenderManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
 
 void RenderManager::RemoveGeometry(Render::Geometry* geometry)
 {
-  auto iter = std::find(mImpl->geometryContainer.begin(), mImpl->geometryContainer.end(), geometry);
-
-  if(iter != mImpl->geometryContainer.end())
-  {
-    mImpl->geometryContainer.Erase(iter);
-  }
+  mImpl->geometryContainer.EraseObject(geometry);
 }
 
 void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
 {
-  DALI_ASSERT_DEBUG(nullptr != geometry);
-
-  // Find the geometry
-  for(auto&& iter : mImpl->geometryContainer)
-  {
-    if(iter == geometry)
-    {
-      iter->AddVertexBuffer(vertexBuffer);
-      break;
-    }
-  }
+  geometry->AddVertexBuffer(vertexBuffer);
 }
 
 void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer)
 {
-  DALI_ASSERT_DEBUG(nullptr != geometry);
-
-  // Find the geometry
-  for(auto&& iter : mImpl->geometryContainer)
-  {
-    if(iter == geometry)
-    {
-      iter->RemoveVertexBuffer(vertexBuffer);
-      break;
-    }
-  }
+  geometry->RemoveVertexBuffer(vertexBuffer);
 }
 
 void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType)
index 90465be..4c4474b 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_PROPERTY_NOTIFICATION_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -19,7 +19,6 @@
  */
 
 // INTERNAL INCLUDES
-#include <dali/devel-api/common/owner-container.h>
 #include <dali/internal/event/common/property-notification-impl.h>
 #include <dali/internal/update/common/property-base.h>
 #include <dali/public-api/object/property-notification.h>
@@ -35,10 +34,7 @@ namespace SceneGraph
 {
 class PropertyNotification;
 
-using PropertyNotificationContainer = OwnerContainer<PropertyNotification*>;
-using PropertyNotificationIter      = PropertyNotificationContainer::Iterator;
-using PropertyNotificationConstIter = PropertyNotificationContainer::ConstIterator;
-using ConditionFunction             = bool (*)(const Dali::PropertyInput&, Dali::Internal::PropertyNotification::RawArgumentContainer&);
+using ConditionFunction = bool (*)(const Dali::PropertyInput&, Dali::Internal::PropertyNotification::RawArgumentContainer&);
 
 /**
  * PropertyNotifications are used to inspect properties of scene graph objects, as part of a scene
index e8f2867..778a758 100644 (file)
@@ -282,11 +282,11 @@ struct UpdateManager::Impl
   ResetterContainer<PropertyResetterBase> propertyResetters; ///< A container of property resetters
   ResetterContainer<NodeResetter>         nodeResetters;     ///< A container of node resetters
 
-  OwnerContainer<Animation*>    animations;            ///< A container of owned animations
-  PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
-  OwnerKeyContainer<Renderer>   renderers;             ///< A container of owned renderers
-  OwnerContainer<TextureSet*>   textureSets;           ///< A container of owned texture sets
-  OwnerContainer<Shader*>       shaders;               ///< A container of owned shaders
+  OwnerContainer<Animation*>            animations;            ///< A container of owned animations
+  OwnerContainer<PropertyNotification*> propertyNotifications; ///< A container of owner property notifications.
+  OwnerKeyContainer<Renderer>           renderers;             ///< A container of owned renderers
+  OwnerContainer<TextureSet*>           textureSets;           ///< A container of owned texture sets
+  OwnerContainer<Shader*>               shaders;               ///< A container of owned shaders
 
   DiscardQueue<Node*, OwnerContainer<Node*>>                         nodeDiscardQueue; ///< Nodes are added here when disconnected from the scene-graph.
   DiscardQueue<Shader*, OwnerContainer<Shader*>>                     shaderDiscardQueue;