You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
6.1 KiB
264 lines
6.1 KiB
2 years ago
|
// 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
|