[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.
This commit is contained in:
Mikhail Pozdnyakov
2019-11-18 21:24:09 +02:00
parent b3fdd2c762
commit 986465e015
3 changed files with 78 additions and 40 deletions

View File

@@ -22,13 +22,13 @@ namespace style {
* A `std::string getID() const` method
*/
template <class T>
class Collection {
class CollectionBase {
public:
using Impl = typename T::Impl;
using WrapperVector = std::vector<std::unique_ptr<T>>;
using ImmutableVector = Immutable<std::vector<Immutable<Impl>>>;
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<T>, const optional<std::string>& = {});
std::unique_ptr<T> 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<T> wrapper);
std::unique_ptr<T> 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 <class T>
Collection<T>::Collection()
: impls(makeMutable<std::vector<Immutable<Impl>>>()) {
}
template <class T, bool persistentImplsOrder = false>
class Collection;
template <class T>
std::size_t Collection<T>::size() const {
class Collection<T, false /*persistentImplsOrder*/> : public CollectionBase<T> {
using Base = CollectionBase<T>;
public:
T* add(std::unique_ptr<T> wrapper, const optional<std::string>& before = nullopt) {
std::size_t index = before ? Base::index(*before) : Base::size();
return Base::add(index, index, std::move(wrapper));
}
std::unique_ptr<T> 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 T>
class Collection<T, true /*persistentImplsOrder*/> : public CollectionBase<T> {
using Base = CollectionBase<T>;
public:
T* add(std::unique_ptr<T> wrapper) {
std::size_t i = implsIndex(wrapper->getID());
return Base::add(Base::size(), i, std::move(wrapper));
}
std::unique_ptr<T> 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 <class T>
using CollectionWithPersistentOrder = Collection<T, true>;
template <class T>
CollectionBase<T>::CollectionBase() : impls(makeMutable<std::vector<Immutable<Impl>>>()) {}
template <class T>
std::size_t CollectionBase<T>::size() const {
return wrappers.size();
}
template <class T>
std::size_t Collection<T>::index(const std::string& id) const {
std::size_t CollectionBase<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 {
T* CollectionBase<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*> CollectionBase<T>::getWrappers() const {
std::vector<T*> result;
result.reserve(wrappers.size());
@@ -92,7 +132,7 @@ std::vector<T*> Collection<T>::getWrappers() const {
}
template <class T>
void Collection<T>::clear() {
void CollectionBase<T>::clear() {
mutate(impls, [&] (auto& impls_) {
impls_.clear();
});
@@ -101,40 +141,37 @@ void Collection<T>::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();
T* CollectionBase<T>::add(std::size_t wrapperIndex, std::size_t implIndex, std::unique_ptr<T> 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 <class T>
std::unique_ptr<T> Collection<T>::remove(const std::string& id) {
std::size_t i = index(id);
if (i >= size()) {
std::unique_ptr<T> CollectionBase<T>::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 <class T>
void Collection<T>::update(const T& wrapper) {
mutate(impls, [&] (auto& impls_) {
impls_.at(this->index(wrapper.getID())) = wrapper.baseImpl;
});
void CollectionBase<T>::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

View File

@@ -2,6 +2,7 @@
#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/style/image_impl.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>

View File

@@ -106,8 +106,8 @@ private:
std::unique_ptr<SpriteLoader> spriteLoader;
std::string glyphURL;
Collection<style::Image> images;
Collection<Source> sources;
CollectionWithPersistentOrder<style::Image> images;
CollectionWithPersistentOrder<Source> sources;
Collection<Layer> layers;
TransitionOptions transitionOptions;
std::unique_ptr<Light> light;