diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-05-31 13:53:48 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-06-05 19:38:08 -0700 |
commit | 9dfc2d924d440560adb2db13c758b2c5b3b7dd47 (patch) | |
tree | 8d1868b5b011676fd0a7d260e0c3560cd36db6b9 /src/mbgl/style/collection.hpp | |
parent | 97eb62fe7cc10fd882f6e361c461900687361460 (diff) | |
download | qtlocation-mapboxgl-9dfc2d924d440560adb2db13c758b2c5b3b7dd47.tar.gz |
[core] Collection-level immutability
Introduce a second level of immutability, over each of the collections held by a style: sources, images, and layers. Tracking immutability at this level allows us to short-circuit significant portions of the RenderStyle update logic via a simple equality check, greatly improving performance.
Diffstat (limited to 'src/mbgl/style/collection.hpp')
-rw-r--r-- | src/mbgl/style/collection.hpp | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/mbgl/style/collection.hpp b/src/mbgl/style/collection.hpp new file mode 100644 index 0000000000..0deb1411b6 --- /dev/null +++ b/src/mbgl/style/collection.hpp @@ -0,0 +1,141 @@ +#pragma once + +#include <mbgl/util/immutable.hpp> +#include <mbgl/util/optional.hpp> + +#include <memory> +#include <string> + +namespace mbgl { +namespace style { + +/* + Manages an ordered collection of elements and their `Immutable<Impl>`s. The latter is + itself stored in an Immutable container. Using immutability at the collection level + allows us to short-circuit significant portions of the RenderStyle update logic via + a simple pointer equality check, greatly improving performance. + + Element types are required to have: + + * An `Impl` inner class type + * An `Immutable<Impl> baseImpl` member + * A `std::string getID() const` method +*/ +template <class T> +class Collection { +public: + using Impl = typename T::Impl; + using WrapperVector = std::vector<std::unique_ptr<T>>; + using ImmutableVector = Immutable<std::vector<Immutable<Impl>>>; + + Collection(); + + std::size_t size() const; + T* get(const std::string&) const; + + std::vector<T*> getWrappers() const; + ImmutableVector getImpls() const { return impls; } + + auto begin() const { return wrappers.begin(); } + auto end() const { return wrappers.end(); } + + void clear(); + + T* add(std::unique_ptr<T>, const optional<std::string>& = {}); + std::unique_ptr<T> remove(const std::string&); + + // 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; + + WrapperVector wrappers; + ImmutableVector impls; +}; + +template <class T> +Collection<T>::Collection() + : impls(makeMutable<std::vector<Immutable<Impl>>>()) { +} + +template <class T> +std::size_t Collection<T>::size() const { + return wrappers.size(); +} + +template <class T> +std::size_t Collection<T>::index(const std::string& id) const { + return std::find_if(wrappers.begin(), wrappers.end(), [&](const auto& e) { + return e->getID() == id; + }) - wrappers.begin(); +} + +template <class T> +T* Collection<T>::get(const std::string& id) const { + std::size_t i = index(id); + return i < size() ? wrappers[i].get() : nullptr; +} + +template <class T> +std::vector<T*> Collection<T>::getWrappers() const { + std::vector<T*> result; + result.reserve(wrappers.size()); + + for (auto& wrapper : wrappers) { + result.push_back(wrapper.get()); + } + + return result; +} + +template <class T> +void Collection<T>::clear() { + mutate(impls, [&] (auto& impls_) { + impls_.clear(); + }); + + wrappers.clear(); +} + +template <class T> +T* Collection<T>::add(std::unique_ptr<T> wrapper, const optional<std::string>& before) { + std::size_t i = before ? index(*before) : size(); + + mutate(impls, [&] (auto& impls_) { + impls_.emplace(impls_.begin() + i, wrapper->baseImpl); + }); + + return wrappers.emplace(wrappers.begin() + i, std::move(wrapper))->get(); +} + +template <class T> +std::unique_ptr<T> Collection<T>::remove(const std::string& id) { + std::size_t i = index(id); + + if (i >= size()) { + return nullptr; + } + + auto source = std::move(wrappers[i]); + + mutate(impls, [&] (auto& impls_) { + impls_.erase(impls_.begin() + i); + }); + + wrappers.erase(wrappers.begin() + i); + + return source; +} + +template <class T> +void Collection<T>::update(const T& wrapper) { + mutate(impls, [&] (auto& impls_) { + impls_.at(this->index(wrapper.getID())) = wrapper.baseImpl; + }); +} + +} // namespace style +} // namespace mbgl |