// 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 #include #include // std::move, std::forward namespace dap { // optional holds an 'optional' contained value. // This is similar to C++17's std::optional. template class optional { template using IsConvertibleToT = typename std::enable_if::value>::type; public: using value_type = T; // constructors inline optional() = default; inline optional(const optional& other); inline optional(optional&& other); template inline optional(const optional& other); template inline optional(optional&& other); template > 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 > inline optional& operator=(U&& value); template inline optional& operator=(const optional& other); template inline optional& operator=(optional&& 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 optional::optional(const optional& other) : val(other.val), set(other.set) {} template optional::optional(optional&& other) : val(std::move(other.val)), set(other.set) {} template template optional::optional(const optional& other) : set(other.has_value()) { if (set) { val = static_cast(other.value()); } } template template optional::optional(optional&& other) : set(other.has_value()) { if (set) { val = static_cast(std::move(other.value())); } } template template optional::optional(U&& value) : val(std::forward(value)), set(true) {} template T& optional::value() { assert(set); return val; } template const T& optional::value() const { assert(set); return val; } template const T& optional::value(const T& defaultValue) const { if (!has_value()) { return defaultValue; } return val; } template optional::operator bool() const noexcept { return set; } template bool optional::has_value() const { return set; } template optional& optional::operator=(const optional& other) { val = other.val; set = other.set; return *this; } template optional& optional::operator=(optional&& other) noexcept { val = std::move(other.val); set = other.set; return *this; } template template optional& optional::operator=(U&& value) { val = std::forward(value); set = true; return *this; } template template optional& optional::operator=(const optional& other) { val = other.val; set = other.set; return *this; } template template optional& optional::operator=(optional&& other) { val = std::move(other.val); set = other.set; return *this; } template const T* optional::operator->() const { assert(set); return &val; } template T* optional::operator->() { assert(set); return &val; } template const T& optional::operator*() const { assert(set); return val; } template T& optional::operator*() { assert(set); return val; } template inline bool operator==(const optional& lhs, const optional& 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 inline bool operator!=(const optional& lhs, const optional& rhs) { return !(lhs == rhs); } template inline bool operator<(const optional& lhs, const optional& rhs) { if (!rhs.has_value()) { return false; } if (!lhs.has_value()) { return true; } return lhs.value() < rhs.value(); } template inline bool operator<=(const optional& lhs, const optional& rhs) { if (!lhs.has_value()) { return true; } if (!rhs.has_value()) { return false; } return lhs.value() <= rhs.value(); } template inline bool operator>(const optional& lhs, const optional& rhs) { if (!lhs.has_value()) { return false; } if (!rhs.has_value()) { return true; } return lhs.value() > rhs.value(); } template inline bool operator>=(const optional& lhs, const optional& rhs) { if (!rhs.has_value()) { return true; } if (!lhs.has_value()) { return false; } return lhs.value() >= rhs.value(); } } // namespace dap #endif // dap_optional_h