summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/base/SkTLazy.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/base/SkTLazy.h')
-rw-r--r--gfx/skia/skia/src/base/SkTLazy.h208
1 files changed, 208 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/base/SkTLazy.h b/gfx/skia/skia/src/base/SkTLazy.h
new file mode 100644
index 0000000000..38b3b373db
--- /dev/null
+++ b/gfx/skia/skia/src/base/SkTLazy.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTLazy_DEFINED
+#define SkTLazy_DEFINED
+
+#include "include/private/base/SkAssert.h"
+
+#include <optional>
+#include <utility>
+
+/**
+ * Efficient way to defer allocating/initializing a class until it is needed
+ * (if ever).
+ */
+template <typename T> class SkTLazy {
+public:
+ SkTLazy() = default;
+ explicit SkTLazy(const T* src) : fValue(src ? std::optional<T>(*src) : std::nullopt) {}
+ SkTLazy(const SkTLazy& that) : fValue(that.fValue) {}
+ SkTLazy(SkTLazy&& that) : fValue(std::move(that.fValue)) {}
+
+ ~SkTLazy() = default;
+
+ SkTLazy& operator=(const SkTLazy& that) {
+ fValue = that.fValue;
+ return *this;
+ }
+
+ SkTLazy& operator=(SkTLazy&& that) {
+ fValue = std::move(that.fValue);
+ return *this;
+ }
+
+ /**
+ * Return a pointer to an instance of the class initialized with 'args'.
+ * If a previous instance had been initialized (either from init() or
+ * set()) it will first be destroyed, so that a freshly initialized
+ * instance is always returned.
+ */
+ template <typename... Args> T* init(Args&&... args) {
+ fValue.emplace(std::forward<Args>(args)...);
+ return this->get();
+ }
+
+ /**
+ * Copy src into this, and return a pointer to a copy of it. Note this
+ * will always return the same pointer, so if it is called on a lazy that
+ * has already been initialized, then this will copy over the previous
+ * contents.
+ */
+ T* set(const T& src) {
+ fValue = src;
+ return this->get();
+ }
+
+ T* set(T&& src) {
+ fValue = std::move(src);
+ return this->get();
+ }
+
+ /**
+ * Destroy the lazy object (if it was created via init() or set())
+ */
+ void reset() {
+ fValue.reset();
+ }
+
+ /**
+ * Returns true if a valid object has been initialized in the SkTLazy,
+ * false otherwise.
+ */
+ bool isValid() const { return fValue.has_value(); }
+
+ /**
+ * Returns the object. This version should only be called when the caller
+ * knows that the object has been initialized.
+ */
+ T* get() {
+ SkASSERT(fValue.has_value());
+ return &fValue.value();
+ }
+ const T* get() const {
+ SkASSERT(fValue.has_value());
+ return &fValue.value();
+ }
+
+ T* operator->() { return this->get(); }
+ const T* operator->() const { return this->get(); }
+
+ T& operator*() {
+ SkASSERT(fValue.has_value());
+ return *fValue;
+ }
+ const T& operator*() const {
+ SkASSERT(fValue.has_value());
+ return *fValue;
+ }
+
+ /**
+ * Like above but doesn't assert if object isn't initialized (in which case
+ * nullptr is returned).
+ */
+ const T* getMaybeNull() const { return fValue.has_value() ? this->get() : nullptr; }
+ T* getMaybeNull() { return fValue.has_value() ? this->get() : nullptr; }
+
+private:
+ std::optional<T> fValue;
+};
+
+/**
+ * A helper built on top of std::optional to do copy-on-first-write. The object is initialized
+ * with a const pointer but provides a non-const pointer accessor. The first time the
+ * accessor is called (if ever) the object is cloned.
+ *
+ * In the following example at most one copy of constThing is made:
+ *
+ * SkTCopyOnFirstWrite<Thing> thing(&constThing);
+ * ...
+ * function_that_takes_a_const_thing_ptr(thing); // constThing is passed
+ * ...
+ * if (need_to_modify_thing()) {
+ * thing.writable()->modifyMe(); // makes a copy of constThing
+ * }
+ * ...
+ * x = thing->readSomething();
+ * ...
+ * if (need_to_modify_thing_now()) {
+ * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe()
+ * }
+ *
+ * consume_a_thing(thing); // could be constThing or a modified copy.
+ */
+template <typename T>
+class SkTCopyOnFirstWrite {
+public:
+ explicit SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
+
+ explicit SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {}
+
+ // Constructor for delayed initialization.
+ SkTCopyOnFirstWrite() : fObj(nullptr) {}
+
+ SkTCopyOnFirstWrite(const SkTCopyOnFirstWrite& that) { *this = that; }
+ SkTCopyOnFirstWrite( SkTCopyOnFirstWrite&& that) { *this = std::move(that); }
+
+ SkTCopyOnFirstWrite& operator=(const SkTCopyOnFirstWrite& that) {
+ fLazy = that.fLazy;
+ fObj = fLazy.has_value() ? &fLazy.value() : that.fObj;
+ return *this;
+ }
+
+ SkTCopyOnFirstWrite& operator=(SkTCopyOnFirstWrite&& that) {
+ fLazy = std::move(that.fLazy);
+ fObj = fLazy.has_value() ? &fLazy.value() : that.fObj;
+ return *this;
+ }
+
+ // Should only be called once, and only if the default constructor was used.
+ void init(const T& initial) {
+ SkASSERT(!fObj);
+ SkASSERT(!fLazy.has_value());
+ fObj = &initial;
+ }
+
+ // If not already initialized, in-place instantiates the writable object
+ template <typename... Args>
+ void initIfNeeded(Args&&... args) {
+ if (!fObj) {
+ SkASSERT(!fLazy.has_value());
+ fObj = &fLazy.emplace(std::forward<Args>(args)...);
+ }
+ }
+
+ /**
+ * Returns a writable T*. The first time this is called the initial object is cloned.
+ */
+ T* writable() {
+ SkASSERT(fObj);
+ if (!fLazy.has_value()) {
+ fLazy = *fObj;
+ fObj = &fLazy.value();
+ }
+ return &fLazy.value();
+ }
+
+ const T* get() const { return fObj; }
+
+ /**
+ * Operators for treating this as though it were a const pointer.
+ */
+
+ const T *operator->() const { return fObj; }
+
+ operator const T*() const { return fObj; }
+
+ const T& operator *() const { return *fObj; }
+
+private:
+ const T* fObj;
+ std::optional<T> fLazy;
+};
+
+#endif