summaryrefslogtreecommitdiff
path: root/src/mbgl/style/collection.hpp
blob: 0deb1411b6df77c0e9f3258e855c891940a31847 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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