diff options
Diffstat (limited to 'src/deps/skia/include/private/SkTOptional.h')
-rw-r--r-- | src/deps/skia/include/private/SkTOptional.h | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/src/deps/skia/include/private/SkTOptional.h b/src/deps/skia/include/private/SkTOptional.h new file mode 100644 index 000000000..f610493b0 --- /dev/null +++ b/src/deps/skia/include/private/SkTOptional.h @@ -0,0 +1,362 @@ +/* + * Copyright 2021 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTOptional_DEFINED +#define SkTOptional_DEFINED + +#include "include/core/SkTypes.h" + +#include <utility> + +namespace skstd { + +/** + * An empty optional is represented with `nullopt`. + */ +struct nullopt_t { + struct tag {}; + + // nullopt_t must not be default-constructible. + explicit constexpr nullopt_t(tag) {} +}; + +static constexpr nullopt_t nullopt{nullopt_t::tag{}}; + +/** + * Simple drop-in replacement for std::optional until we move to C++17. This does not have all of + * std::optional's capabilities, but it covers our needs for the time being. + */ +template<typename T> +class optional { +public: + optional(const T& value) + : fHasValue(true) { + new(&fPayload.fValue) T(value); + } + + optional(T&& value) + : fHasValue(true) { + new(&fPayload.fValue) T(std::move(value)); + } + + optional() {} + + optional(const optional& other) { + *this = other; + } + + // Construction with nullopt is the same as default construction. + optional(nullopt_t) : optional() {} + + // We need a non-const copy constructor because otherwise optional(nonConstSrc) isn't an exact + // match for the copy constructor, and we'd end up invoking the Args&&... template by mistake. + optional(optional& other) { + *this = other; + } + + optional(optional&& other) { + *this = std::move(other); + } + + template<typename... Args> + optional(Args&&... args) { + fHasValue = true; + new(&fPayload.fValue) T(std::forward<Args>(args)...); + } + + ~optional() { + this->reset(); + } + + optional& operator=(const optional& other) { + if (this != &other) { + if (fHasValue) { + if (other.fHasValue) { + fPayload.fValue = other.fPayload.fValue; + } else { + this->reset(); + } + } else { + if (other.fHasValue) { + fHasValue = true; + new (&fPayload.fValue) T(other.fPayload.fValue); + } else { + // do nothing, no value on either side + } + } + } + return *this; + } + + optional& operator=(optional&& other) { + if (this != &other) { + if (fHasValue) { + if (other.fHasValue) { + fPayload.fValue = std::move(other.fPayload.fValue); + } else { + this->reset(); + } + } else { + if (other.fHasValue) { + fHasValue = true; + new (&fPayload.fValue) T(std::move(other.fPayload.fValue)); + } else { + // do nothing, no value on either side + } + } + } + return *this; + } + + template<typename... Args> + optional& emplace(Args&&... args) { + this->reset(); + fHasValue = true; + new(&fPayload.fValue) T(std::forward<Args>(args)...); + return *this; + } + + template<typename U, typename... Args> + optional& emplace(std::initializer_list<U> il, Args&&... args) { + this->reset(); + fHasValue = true; + new(&fPayload.fValue) T(il, std::forward<Args>(args)...); + return *this; + } + + // Assignment to nullopt is the same as reset(). + optional& operator=(nullopt_t) { + this->reset(); + return *this; + } + + T& operator*() & { + SkASSERT(fHasValue); + return fPayload.fValue; + } + + const T& operator*() const& { + SkASSERT(fHasValue); + return fPayload.fValue; + } + + T&& operator*() && { + SkASSERT(fHasValue); + return std::move(fPayload.fValue); + } + + const T&& operator*() const&& { + SkASSERT(fHasValue); + return std::move(fPayload.fValue); + } + + const T& value() const& { + SkASSERT_RELEASE(fHasValue); + return **this; + } + + T& value() & { + SkASSERT_RELEASE(fHasValue); + return **this; + } + + const T&& value() const&& { + SkASSERT_RELEASE(fHasValue); + return std::move(**this); + } + + T&& value() && { + SkASSERT_RELEASE(fHasValue); + return std::move(**this); + } + + T* operator->() { + return &**this; + } + + const T* operator->() const { + return &**this; + } + + template<typename U> + T value_or(U&& value) const& { + return this->has_value() ? **this : static_cast<T>(std::forward<U>(value)); + } + + template<typename U> + T value_or(U&& value) && { + return this->has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(value)); + } + + bool has_value() const { + return fHasValue; + } + + explicit operator bool() const { + return this->has_value(); + } + + void reset() { + if (fHasValue) { + fPayload.fValue.~T(); + fHasValue = false; + } + } + +private: + union Payload { + T fValue; + + Payload() {} + + ~Payload() {} + } fPayload; + + bool fHasValue = false; +}; + +// Comparison operators for optional x optional +template <typename T, typename U> bool operator==(const optional<T>& a, const optional<U>& b) { + return (a.has_value() != b.has_value()) ? false : + !a.has_value() ? true : + (*a == *b); +} + +template <typename T, typename U> bool operator!=(const optional<T>& a, const optional<U>& b) { + return (a.has_value() != b.has_value()) ? true : + !a.has_value() ? false : + (*a != *b); +} + +template <typename T, typename U> bool operator<(const optional<T>& a, const optional<U>& b) { + return !b.has_value() ? false : + !a.has_value() ? true : + (*a < *b); +} + +template <typename T, typename U> bool operator<=(const optional<T>& a, const optional<U>& b) { + return !a.has_value() ? true : + !b.has_value() ? false : + (*a <= *b); +} + +template <typename T, typename U> bool operator>(const optional<T>& a, const optional<U>& b) { + return !a.has_value() ? false : + !b.has_value() ? true : + (*a > *b); +} + +template <typename T, typename U> bool operator>=(const optional<T>& a, const optional<U>& b) { + return !b.has_value() ? true : + !a.has_value() ? false : + (*a >= *b); +} + +// Comparison operators for optional x nullopt +template <typename T> bool operator==(const optional<T>& a, nullopt_t) { + return !a.has_value(); +} + +template <typename T> bool operator!=(const optional<T>& a, nullopt_t) { + return a.has_value(); +} + +template <typename T> bool operator<(const optional<T>&, nullopt_t) { + return false; +} + +template <typename T> bool operator<=(const optional<T>& a, nullopt_t) { + return !a.has_value(); +} + +template <typename T> bool operator>(const optional<T>& a, nullopt_t) { + return a.has_value(); +} + +template <typename T> +bool operator>=(const optional<T>&, nullopt_t) { + return true; +} + +// Comparison operators for nullopt x optional +template <typename U> bool operator==(nullopt_t, const optional<U>& b) { + return !b.has_value(); +} + +template <typename U> bool operator!=(nullopt_t, const optional<U>& b) { + return b.has_value(); +} + +template <typename U> bool operator<(nullopt_t, const optional<U>& b) { + return b.has_value(); +} + +template <typename U> bool operator<=(nullopt_t, const optional<U>&) { + return true; +} + +template <typename U> bool operator>(nullopt_t, const optional<U>&) { + return false; +} + +template <typename U> bool operator>=(nullopt_t, const optional<U>& b) { + return !b.has_value(); +} + +// Comparison operators for optional x value +template <typename T, typename U> bool operator==(const optional<T>& a, const U& b) { + return a.has_value() && (*a == b); +} + +template <typename T, typename U> bool operator!=(const optional<T>& a, const U& b) { + return !a.has_value() || (*a != b); +} + +template <typename T, typename U> bool operator<(const optional<T>& a, const U& b) { + return !a.has_value() || (*a < b); +} + +template <typename T, typename U> bool operator<=(const optional<T>& a, const U& b) { + return !a.has_value() || (*a <= b); +} + +template <typename T, typename U> bool operator>(const optional<T>& a, const U& b) { + return a.has_value() && (*a > b); +} + +template <typename T, typename U> bool operator>=(const optional<T>& a, const U& b) { + return a.has_value() && (*a >= b); +} + +// Comparison operators for value x optional +template <typename T, typename U> bool operator==(const T& a, const optional<U>& b) { + return b.has_value() && (a == *b); +} + +template <typename T, typename U> bool operator!=(const T& a, const optional<U>& b) { + return !b.has_value() || (a != *b); +} + +template <typename T, typename U> bool operator<(const T& a, const optional<U>& b) { + return b.has_value() && (a < *b); +} + +template <typename T, typename U> bool operator<=(const T& a, const optional<U>& b) { + return b.has_value() && (a <= *b); +} + +template <typename T, typename U> bool operator>(const T& a, const optional<U>& b) { + return !b.has_value() || (a > *b); +} + +template <typename T, typename U> bool operator>=(const T& a, const optional<U>& b) { + return !b.has_value() || (a >= *b); +} + +} // namespace skstd + +#endif |