summaryrefslogtreecommitdiff
path: root/include/mbgl/util
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2017-04-25 18:20:26 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-05-12 11:26:27 -0700
commitc2a5894f2dbe9982830066ab9347b059e6e7d845 (patch)
treec09363c2025b80265de195969ee56cc64e567e70 /include/mbgl/util
parentd3f23b83d42de8ef23ea1dbd8abfc6276009531f (diff)
downloadqtlocation-mapboxgl-c2a5894f2dbe9982830066ab9347b059e6e7d845.tar.gz
[core] Immutable Impls
Diffstat (limited to 'include/mbgl/util')
-rw-r--r--include/mbgl/util/immutable.hpp127
-rw-r--r--include/mbgl/util/tileset.hpp5
2 files changed, 132 insertions, 0 deletions
diff --git a/include/mbgl/util/immutable.hpp b/include/mbgl/util/immutable.hpp
new file mode 100644
index 0000000000..1d6ff4079a
--- /dev/null
+++ b/include/mbgl/util/immutable.hpp
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <memory>
+
+namespace mbgl {
+
+/**
+ * `Mutable<T>` is a non-nullable uniquely owning reference to a `T`. It can be efficiently converted
+ * to `Immutable<T>`.
+ *
+ * The lifecycle of `Mutable<T>` and `Immutable<T>` is as follows:
+ *
+ * 1. Create a `Mutable<T>` using `makeMutable(...)`
+ * 2. Mutate it freely
+ * 3. When you're ready to freeze its state and enable safe cross-thread sharing, move assign or
+ * move construct it to `Immutable<T>`
+ *
+ * The reason that `Mutable<T>` exists, rather than simply using a `std::unique_ptr<T>`, is to take advantage
+ * of the underlying single-allocation optimization provided by `std::make_shared`.
+ */
+template <class T>
+class Mutable {
+public:
+ Mutable(Mutable&&) = default;
+ Mutable& operator=(Mutable&&) = default;
+
+ Mutable(const Mutable&) = delete;
+ Mutable& operator=(const Mutable&) = delete;
+
+ T* get() { return ptr.get(); }
+ T* operator->() { return ptr.get(); }
+ T& operator*() { return *ptr; }
+
+private:
+ Mutable(std::shared_ptr<T>&& s)
+ : ptr(std::move(s)) {}
+
+ std::shared_ptr<T> ptr;
+
+ template <class S> friend class Immutable;
+ template <class S, class... Args> friend Mutable<S> makeMutable(Args&&...);
+};
+
+template <class T, class... Args>
+Mutable<T> makeMutable(Args&&... args) {
+ return Mutable<T>(std::make_shared<T>(std::forward<Args>(args)...));
+}
+
+/**
+ * `Immutable<T>` is a non-nullable shared reference to a `const T`. Construction requires
+ * a transfer of unique ownership from a `Mutable<T>`; once constructed it has the same behavior
+ * as `std::shared_ptr<const T>` but with better indication of intent.
+ *
+ * Normally one should not share state between threads because it's difficult to verify the
+ * absence of read/write data races. `Immutable` provides a guarantee that no writes are
+ * possible, and instances therefore can be freely transferred and shared between threads.
+ */
+template <class T>
+class Immutable {
+public:
+ template <class S>
+ Immutable(Mutable<S>&& s)
+ : ptr(std::const_pointer_cast<const S>(std::move(s.ptr))) {}
+
+ template <class S>
+ Immutable(Immutable<S>&& s)
+ : ptr(std::move(s.ptr)) {}
+
+ template <class S>
+ Immutable(const Immutable<S>& s)
+ : ptr(s.ptr) {}
+
+ template <class S>
+ Immutable& operator=(Mutable<S>&& s) {
+ ptr = std::const_pointer_cast<const S>(std::move(s.ptr));
+ return *this;
+ }
+
+ template <class S>
+ Immutable& operator=(Immutable<S>&& s) {
+ ptr = std::move(s.ptr);
+ return *this;
+ }
+
+ template <class S>
+ Immutable& operator=(const Immutable<S>& s) {
+ ptr = s.ptr;
+ return *this;
+ }
+
+ const T* get() const { return ptr.get(); }
+ const T* operator->() const { return ptr.get(); }
+ const T& operator*() const { return *ptr; }
+
+ friend bool operator==(const Immutable<T>& lhs, const Immutable<T>& rhs) {
+ return lhs.ptr == rhs.ptr;
+ }
+
+ friend bool operator!=(const Immutable<T>& lhs, const Immutable<T>& rhs) {
+ return lhs.ptr != rhs.ptr;
+ }
+
+private:
+ Immutable(std::shared_ptr<const T>&& s)
+ : ptr(std::move(s)) {}
+
+ std::shared_ptr<const T> ptr;
+
+ template <class S> friend class Immutable;
+ template <class S> friend class EnableImmutableFromThis;
+ template <class S, class U> friend Immutable<S> staticImmutableCast(const Immutable<U>&);
+};
+
+template <class T>
+class EnableImmutableFromThis : public std::enable_shared_from_this<const T> {
+public:
+ Immutable<T> immutableFromThis() const {
+ return Immutable<T>(this->shared_from_this());
+ }
+};
+
+template <class S, class U>
+Immutable<S> staticImmutableCast(const Immutable<U>& u) {
+ return Immutable<S>(std::static_pointer_cast<const S>(u.ptr));
+}
+
+} // namespace mbgl
diff --git a/include/mbgl/util/tileset.hpp b/include/mbgl/util/tileset.hpp
index 1f28a5039a..1256e9fe96 100644
--- a/include/mbgl/util/tileset.hpp
+++ b/include/mbgl/util/tileset.hpp
@@ -18,6 +18,11 @@ public:
Scheme scheme = Scheme::XYZ;
// TileJSON also includes center, zoom, and bounds, but they are not used by mbgl.
+
+ friend bool operator==(const Tileset& lhs, const Tileset& rhs) {
+ return std::tie(lhs.tiles, lhs.zoomRange, lhs.attribution, lhs.scheme)
+ == std::tie(rhs.tiles, rhs.zoomRange, rhs.attribution, rhs.scheme);
+ }
};
} // namespace mbgl