| // Copyright 2019 Google LLC | |
| // | |
| // 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 | |
| // | |
| // https://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 dap_optional_h | |
| #define dap_optional_h | |
| #include <assert.h> | |
| #include <type_traits> | |
| #include <utility> // std::move, std::forward | |
| namespace dap { | |
| // optional holds an 'optional' contained value. | |
| // This is similar to C++17's std::optional. | |
| template <typename T> | |
| class optional { | |
| template <typename U> | |
| using IsConvertibleToT = | |
| typename std::enable_if<std::is_convertible<U, T>::value>::type; | |
| public: | |
| using value_type = T; | |
| // constructors | |
| inline optional() = default; | |
| inline optional(const optional& other); | |
| inline optional(optional&& other); | |
| template <typename U> | |
| inline optional(const optional<U>& other); | |
| template <typename U> | |
| inline optional(optional<U>&& other); | |
| template <typename U = value_type, typename = IsConvertibleToT<U>> | |
| inline optional(U&& value); | |
| // value() returns the contained value. | |
| // If the optional does not contain a value, then value() will assert. | |
| inline T& value(); | |
| inline const T& value() const; | |
| // value() returns the contained value, or defaultValue if the optional does | |
| // not contain a value. | |
| inline const T& value(const T& defaultValue) const; | |
| // operator bool() returns true if the optional contains a value. | |
| inline explicit operator bool() const noexcept; | |
| // has_value() returns true if the optional contains a value. | |
| inline bool has_value() const; | |
| // assignment | |
| inline optional& operator=(const optional& other); | |
| inline optional& operator=(optional&& other) noexcept; | |
| template <typename U = T, typename = IsConvertibleToT<U>> | |
| inline optional& operator=(U&& value); | |
| template <typename U> | |
| inline optional& operator=(const optional<U>& other); | |
| template <typename U> | |
| inline optional& operator=(optional<U>&& other); | |
| // value access | |
| inline const T* operator->() const; | |
| inline T* operator->(); | |
| inline const T& operator*() const; | |
| inline T& operator*(); | |
| private: | |
| T val{}; | |
| bool set = false; | |
| }; | |
| template <typename T> | |
| optional<T>::optional(const optional& other) : val(other.val), set(other.set) {} | |
| template <typename T> | |
| optional<T>::optional(optional&& other) | |
| : val(std::move(other.val)), set(other.set) {} | |
| template <typename T> | |
| template <typename U> | |
| optional<T>::optional(const optional<U>& other) : set(other.has_value()) { | |
| if (set) { | |
| val = static_cast<T>(other.value()); | |
| } | |
| } | |
| template <typename T> | |
| template <typename U> | |
| optional<T>::optional(optional<U>&& other) : set(other.has_value()) { | |
| if (set) { | |
| val = static_cast<T>(std::move(other.value())); | |
| } | |
| } | |
| template <typename T> | |
| template <typename U /*= T*/, typename> | |
| optional<T>::optional(U&& value) : val(std::forward<U>(value)), set(true) {} | |
| template <typename T> | |
| T& optional<T>::value() { | |
| assert(set); | |
| return val; | |
| } | |
| template <typename T> | |
| const T& optional<T>::value() const { | |
| assert(set); | |
| return val; | |
| } | |
| template <typename T> | |
| const T& optional<T>::value(const T& defaultValue) const { | |
| if (!has_value()) { | |
| return defaultValue; | |
| } | |
| return val; | |
| } | |
| template <typename T> | |
| optional<T>::operator bool() const noexcept { | |
| return set; | |
| } | |
| template <typename T> | |
| bool optional<T>::has_value() const { | |
| return set; | |
| } | |
| template <typename T> | |
| optional<T>& optional<T>::operator=(const optional& other) { | |
| val = other.val; | |
| set = other.set; | |
| return *this; | |
| } | |
| template <typename T> | |
| optional<T>& optional<T>::operator=(optional&& other) noexcept { | |
| val = std::move(other.val); | |
| set = other.set; | |
| return *this; | |
| } | |
| template <typename T> | |
| template <typename U /* = T */, typename> | |
| optional<T>& optional<T>::operator=(U&& value) { | |
| val = std::forward<U>(value); | |
| set = true; | |
| return *this; | |
| } | |
| template <typename T> | |
| template <typename U> | |
| optional<T>& optional<T>::operator=(const optional<U>& other) { | |
| val = other.val; | |
| set = other.set; | |
| return *this; | |
| } | |
| template <typename T> | |
| template <typename U> | |
| optional<T>& optional<T>::operator=(optional<U>&& other) { | |
| val = std::move(other.val); | |
| set = other.set; | |
| return *this; | |
| } | |
| template <typename T> | |
| const T* optional<T>::operator->() const { | |
| assert(set); | |
| return &val; | |
| } | |
| template <typename T> | |
| T* optional<T>::operator->() { | |
| assert(set); | |
| return &val; | |
| } | |
| template <typename T> | |
| const T& optional<T>::operator*() const { | |
| assert(set); | |
| return val; | |
| } | |
| template <typename T> | |
| T& optional<T>::operator*() { | |
| assert(set); | |
| return val; | |
| } | |
| template <class T, class U> | |
| inline bool operator==(const optional<T>& lhs, const optional<U>& rhs) { | |
| if (!lhs.has_value() && !rhs.has_value()) { | |
| return true; | |
| } | |
| if (!lhs.has_value() || !rhs.has_value()) { | |
| return false; | |
| } | |
| return lhs.value() == rhs.value(); | |
| } | |
| template <class T, class U> | |
| inline bool operator!=(const optional<T>& lhs, const optional<U>& rhs) { | |
| return !(lhs == rhs); | |
| } | |
| template <class T, class U> | |
| inline bool operator<(const optional<T>& lhs, const optional<U>& rhs) { | |
| if (!rhs.has_value()) { | |
| return false; | |
| } | |
| if (!lhs.has_value()) { | |
| return true; | |
| } | |
| return lhs.value() < rhs.value(); | |
| } | |
| template <class T, class U> | |
| inline bool operator<=(const optional<T>& lhs, const optional<U>& rhs) { | |
| if (!lhs.has_value()) { | |
| return true; | |
| } | |
| if (!rhs.has_value()) { | |
| return false; | |
| } | |
| return lhs.value() <= rhs.value(); | |
| } | |
| template <class T, class U> | |
| inline bool operator>(const optional<T>& lhs, const optional<U>& rhs) { | |
| if (!lhs.has_value()) { | |
| return false; | |
| } | |
| if (!rhs.has_value()) { | |
| return true; | |
| } | |
| return lhs.value() > rhs.value(); | |
| } | |
| template <class T, class U> | |
| inline bool operator>=(const optional<T>& lhs, const optional<U>& rhs) { | |
| if (!rhs.has_value()) { | |
| return true; | |
| } | |
| if (!lhs.has_value()) { | |
| return false; | |
| } | |
| return lhs.value() >= rhs.value(); | |
| } | |
| } // namespace dap | |
| #endif // dap_optional_h |