| /* | |
| * Copyright (C) 2015 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #ifndef AAPT_MAYBE_H | |
| #define AAPT_MAYBE_H | |
| #include <type_traits> | |
| #include <utility> | |
| #include "android-base/logging.h" | |
| #include "util/TypeTraits.h" | |
| namespace aapt { | |
| /** | |
| * Either holds a valid value of type T, or holds Nothing. | |
| * The value is stored inline in this structure, so no | |
| * heap memory is used when creating a Maybe<T> object. | |
| */ | |
| template <typename T> | |
| class Maybe { | |
| public: | |
| /** | |
| * Construct Nothing. | |
| */ | |
| Maybe(); | |
| ~Maybe(); | |
| Maybe(const Maybe& rhs); | |
| template <typename U> | |
| Maybe(const Maybe<U>& rhs); // NOLINT(google-explicit-constructor) | |
| Maybe(Maybe&& rhs) noexcept; | |
| template <typename U> | |
| Maybe(Maybe<U>&& rhs); // NOLINT(google-explicit-constructor) | |
| Maybe& operator=(const Maybe& rhs); | |
| template <typename U> | |
| Maybe& operator=(const Maybe<U>& rhs); | |
| Maybe& operator=(Maybe&& rhs) noexcept; | |
| template <typename U> | |
| Maybe& operator=(Maybe<U>&& rhs); | |
| /** | |
| * Construct a Maybe holding a value. | |
| */ | |
| Maybe(const T& value); // NOLINT(google-explicit-constructor) | |
| /** | |
| * Construct a Maybe holding a value. | |
| */ | |
| Maybe(T&& value); // NOLINT(google-explicit-constructor) | |
| /** | |
| * True if this holds a value, false if | |
| * it holds Nothing. | |
| */ | |
| explicit operator bool() const; | |
| /** | |
| * Gets the value if one exists, or else | |
| * panics. | |
| */ | |
| T& value(); | |
| /** | |
| * Gets the value if one exists, or else | |
| * panics. | |
| */ | |
| const T& value() const; | |
| T value_or_default(const T& def) const; | |
| private: | |
| template <typename U> | |
| friend class Maybe; | |
| template <typename U> | |
| Maybe& copy(const Maybe<U>& rhs); | |
| template <typename U> | |
| Maybe& move(Maybe<U>&& rhs); | |
| void destroy(); | |
| bool nothing_; | |
| typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; | |
| }; | |
| template <typename T> | |
| Maybe<T>::Maybe() : nothing_(true) {} | |
| template <typename T> | |
| Maybe<T>::~Maybe() { | |
| if (!nothing_) { | |
| destroy(); | |
| } | |
| } | |
| template <typename T> | |
| Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) { | |
| if (!rhs.nothing_) { | |
| new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_)); | |
| } | |
| } | |
| template <typename T> | |
| template <typename U> | |
| Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) { | |
| if (!rhs.nothing_) { | |
| new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); | |
| } | |
| } | |
| template <typename T> | |
| Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) { | |
| if (!rhs.nothing_) { | |
| rhs.nothing_ = true; | |
| // Move the value from rhs. | |
| new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_))); | |
| rhs.destroy(); | |
| } | |
| } | |
| template <typename T> | |
| template <typename U> | |
| Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) { | |
| if (!rhs.nothing_) { | |
| rhs.nothing_ = true; | |
| // Move the value from rhs. | |
| new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); | |
| rhs.destroy(); | |
| } | |
| } | |
| template <typename T> | |
| inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) { | |
| // Delegate to the actual assignment. | |
| return copy(rhs); | |
| } | |
| template <typename T> | |
| template <typename U> | |
| inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) { | |
| return copy(rhs); | |
| } | |
| template <typename T> | |
| template <typename U> | |
| Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) { | |
| if (nothing_ && rhs.nothing_) { | |
| // Both are nothing, nothing to do. | |
| return *this; | |
| } else if (!nothing_ && !rhs.nothing_) { | |
| // We both are something, so assign rhs to us. | |
| reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_); | |
| } else if (nothing_) { | |
| // We are nothing but rhs is something. | |
| nothing_ = rhs.nothing_; | |
| // Copy the value from rhs. | |
| new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); | |
| } else { | |
| // We are something but rhs is nothing, so destroy our value. | |
| nothing_ = rhs.nothing_; | |
| destroy(); | |
| } | |
| return *this; | |
| } | |
| template <typename T> | |
| inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept { | |
| // Delegate to the actual assignment. | |
| return move(std::forward<Maybe<T>>(rhs)); | |
| } | |
| template <typename T> | |
| template <typename U> | |
| inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) { | |
| return move(std::forward<Maybe<U>>(rhs)); | |
| } | |
| template <typename T> | |
| template <typename U> | |
| Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) { | |
| if (nothing_ && rhs.nothing_) { | |
| // Both are nothing, nothing to do. | |
| return *this; | |
| } else if (!nothing_ && !rhs.nothing_) { | |
| // We both are something, so move assign rhs to us. | |
| rhs.nothing_ = true; | |
| reinterpret_cast<T&>(storage_) = | |
| std::move(reinterpret_cast<U&>(rhs.storage_)); | |
| rhs.destroy(); | |
| } else if (nothing_) { | |
| // We are nothing but rhs is something. | |
| nothing_ = false; | |
| rhs.nothing_ = true; | |
| // Move the value from rhs. | |
| new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); | |
| rhs.destroy(); | |
| } else { | |
| // We are something but rhs is nothing, so destroy our value. | |
| nothing_ = true; | |
| destroy(); | |
| } | |
| return *this; | |
| } | |
| template <typename T> | |
| Maybe<T>::Maybe(const T& value) : nothing_(false) { | |
| new (&storage_) T(value); | |
| } | |
| template <typename T> | |
| Maybe<T>::Maybe(T&& value) : nothing_(false) { | |
| new (&storage_) T(std::forward<T>(value)); | |
| } | |
| template <typename T> | |
| Maybe<T>::operator bool() const { | |
| return !nothing_; | |
| } | |
| template <typename T> | |
| T& Maybe<T>::value() { | |
| CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; | |
| return reinterpret_cast<T&>(storage_); | |
| } | |
| template <typename T> | |
| const T& Maybe<T>::value() const { | |
| CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; | |
| return reinterpret_cast<const T&>(storage_); | |
| } | |
| template <typename T> | |
| T Maybe<T>::value_or_default(const T& def) const { | |
| if (nothing_) { | |
| return def; | |
| } | |
| return reinterpret_cast<const T&>(storage_); | |
| } | |
| template <typename T> | |
| void Maybe<T>::destroy() { | |
| reinterpret_cast<T&>(storage_).~T(); | |
| } | |
| template <typename T> | |
| inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) { | |
| return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value)); | |
| } | |
| template <typename T> | |
| inline Maybe<T> make_nothing() { | |
| return Maybe<T>(); | |
| } | |
| // Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined. | |
| // That way the compiler will show an error at the callsite when comparing two Maybe<> objects | |
| // whose inner types can't be compared. | |
| template <typename T, typename U> | |
| typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, | |
| const Maybe<U>& b) { | |
| if (a && b) { | |
| return a.value() == b.value(); | |
| } else if (!a && !b) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| template <typename T, typename U> | |
| typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, | |
| const U& b) { | |
| return a ? a.value() == b : false; | |
| } | |
| // Same as operator== but negated. | |
| template <typename T, typename U> | |
| typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(const Maybe<T>& a, | |
| const Maybe<U>& b) { | |
| return !(a == b); | |
| } | |
| template <typename T, typename U> | |
| typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a, | |
| const Maybe<U>& b) { | |
| if (a && b) { | |
| return a.value() < b.value(); | |
| } else if (!a && !b) { | |
| return false; | |
| } | |
| return !a; | |
| } | |
| } // namespace aapt | |
| #endif // AAPT_MAYBE_H |