From 986465e015132dccb5812583b4b1d05083ed9db6 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 18 Nov 2019 21:24:09 +0200 Subject: [PATCH] [core] Introduce style::CollectionWithPersistentOrder So that we do not unnecessarily remove and re-add sources and images if their order has been modified in the updated style. --- src/mbgl/style/collection.hpp | 113 ++++++++++++++++++++++------------ src/mbgl/style/style_impl.cpp | 1 + src/mbgl/style/style_impl.hpp | 4 +- 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/mbgl/style/collection.hpp b/src/mbgl/style/collection.hpp index 0deb1411b..91244cb71 100644 --- a/src/mbgl/style/collection.hpp +++ b/src/mbgl/style/collection.hpp @@ -22,13 +22,13 @@ namespace style { * A `std::string getID() const` method */ template -class Collection { +class CollectionBase { public: using Impl = typename T::Impl; using WrapperVector = std::vector>; using ImmutableVector = Immutable>>; - Collection(); + CollectionBase(); std::size_t size() const; T* get(const std::string&) const; @@ -41,46 +41,86 @@ public: void clear(); - T* add(std::unique_ptr, const optional& = {}); - std::unique_ptr remove(const std::string&); - +protected: + std::size_t index(const std::string&) const; + T* add(std::size_t wrapperIndex, std::size_t implIndex, std::unique_ptr wrapper); + std::unique_ptr remove(std::size_t wrapperIndex, std::size_t implIndex); // Must be called whenever an element of the collection is internally mutated. // Typically, each element permits registration of an observer, and the observer // should call this method. - void update(const T&); - -private: - std::size_t index(const std::string&) const; + void update(std::size_t implIndex, const T&); WrapperVector wrappers; ImmutableVector impls; }; -template -Collection::Collection() - : impls(makeMutable>>()) { -} +template +class Collection; template -std::size_t Collection::size() const { +class Collection : public CollectionBase { + using Base = CollectionBase; + +public: + T* add(std::unique_ptr wrapper, const optional& before = nullopt) { + std::size_t index = before ? Base::index(*before) : Base::size(); + return Base::add(index, index, std::move(wrapper)); + } + std::unique_ptr remove(const std::string& id) { + std::size_t index = Base::index(id); + return Base::remove(index, index); + } + void update(const T& wrapper) { Base::update(Base::index(wrapper.getID()), wrapper); } +}; + +template +class Collection : public CollectionBase { + using Base = CollectionBase; + +public: + T* add(std::unique_ptr wrapper) { + std::size_t i = implsIndex(wrapper->getID()); + return Base::add(Base::size(), i, std::move(wrapper)); + } + + std::unique_ptr remove(const std::string& id) { return Base::remove(Base::index(id), implsIndex(id)); } + + void update(const T& wrapper) { Base::update(implsIndex(wrapper.getID()), wrapper); } + +private: + std::size_t implsIndex(const std::string& id) const { + const auto& impls_ = *Base::impls; + auto it = std::lower_bound( + impls_.begin(), impls_.end(), id, [](const auto& a, const std::string& b) { return a->id < b; }); + return it - impls_.begin(); + } +}; +template +using CollectionWithPersistentOrder = Collection; + +template +CollectionBase::CollectionBase() : impls(makeMutable>>()) {} + +template +std::size_t CollectionBase::size() const { return wrappers.size(); } template -std::size_t Collection::index(const std::string& id) const { +std::size_t CollectionBase::index(const std::string& id) const { return std::find_if(wrappers.begin(), wrappers.end(), [&](const auto& e) { return e->getID() == id; }) - wrappers.begin(); } template -T* Collection::get(const std::string& id) const { +T* CollectionBase::get(const std::string& id) const { std::size_t i = index(id); return i < size() ? wrappers[i].get() : nullptr; } template -std::vector Collection::getWrappers() const { +std::vector CollectionBase::getWrappers() const { std::vector result; result.reserve(wrappers.size()); @@ -92,7 +132,7 @@ std::vector Collection::getWrappers() const { } template -void Collection::clear() { +void CollectionBase::clear() { mutate(impls, [&] (auto& impls_) { impls_.clear(); }); @@ -101,40 +141,37 @@ void Collection::clear() { } template -T* Collection::add(std::unique_ptr wrapper, const optional& before) { - std::size_t i = before ? index(*before) : size(); +T* CollectionBase::add(std::size_t wrapperIndex, std::size_t implIndex, std::unique_ptr wrapper) { + assert(wrapperIndex <= size()); + assert(implIndex <= size()); + mutate(impls, [&](auto& impls_) { impls_.emplace(impls_.begin() + implIndex, wrapper->baseImpl); }); - mutate(impls, [&] (auto& impls_) { - impls_.emplace(impls_.begin() + i, wrapper->baseImpl); - }); - - return wrappers.emplace(wrappers.begin() + i, std::move(wrapper))->get(); + return wrappers.emplace(wrappers.begin() + wrapperIndex, std::move(wrapper))->get(); } template -std::unique_ptr Collection::remove(const std::string& id) { - std::size_t i = index(id); - - if (i >= size()) { +std::unique_ptr CollectionBase::remove(std::size_t wrapperIndex, std::size_t implIndex) { + if (wrapperIndex >= size()) { return nullptr; } + assert(implIndex < size()); - auto source = std::move(wrappers[i]); + auto source = std::move(wrappers[wrapperIndex]); - mutate(impls, [&] (auto& impls_) { - impls_.erase(impls_.begin() + i); - }); + mutate(impls, [&](auto& impls_) { impls_.erase(impls_.begin() + implIndex); }); - wrappers.erase(wrappers.begin() + i); + wrappers.erase(wrappers.begin() + wrapperIndex); return source; } template -void Collection::update(const T& wrapper) { - mutate(impls, [&] (auto& impls_) { - impls_.at(this->index(wrapper.getID())) = wrapper.baseImpl; - }); +void CollectionBase::update(std::size_t implIndex, const T& wrapper) { + if (implIndex >= size()) { + assert(false); + return; + } + mutate(impls, [&](auto& impls_) { impls_.at(implIndex) = wrapper.baseImpl; }); } } // namespace style diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 95a39819f..ef1f8436f 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp index 4c56f6785..c4c0a9a41 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -106,8 +106,8 @@ private: std::unique_ptr spriteLoader; std::string glyphURL; - Collection images; - Collection sources; + CollectionWithPersistentOrder images; + CollectionWithPersistentOrder sources; Collection layers; TransitionOptions transitionOptions; std::unique_ptr light;