| // 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 |