From 1d055261b4144dbf86b2658437015b15d4dd9bff Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 4 Sep 2022 00:32:56 +0100 Subject: initial --- include/jsoncons/detail/optional.hpp | 483 +++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 include/jsoncons/detail/optional.hpp (limited to 'include/jsoncons/detail/optional.hpp') diff --git a/include/jsoncons/detail/optional.hpp b/include/jsoncons/detail/optional.hpp new file mode 100644 index 0000000..492cd76 --- /dev/null +++ b/include/jsoncons/detail/optional.hpp @@ -0,0 +1,483 @@ +// Copyright 2019 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_OPTIONAL_HPP +#define JSONCONS_DETAIL_OPTIONAL_HPP + +#include // placement new +#include +#include // std::swap +#include +#include + +namespace jsoncons +{ +namespace detail +{ + template + class optional; + + template + struct is_constructible_or_convertible_from_optional + : std::integral_constant< + bool, std::is_constructible&>::value || + std::is_constructible&&>::value || + std::is_constructible&>::value || + std::is_constructible&&>::value || + std::is_convertible&, T1>::value || + std::is_convertible&&, T1>::value || + std::is_convertible&, T1>::value || + std::is_convertible&&, T1>::value> {}; + + template + struct is_constructible_convertible_or_assignable_from_optional + : std::integral_constant< + bool, is_constructible_or_convertible_from_optional::value || + std::is_assignable&>::value || + std::is_assignable&&>::value || + std::is_assignable&>::value || + std::is_assignable&&>::value> {}; + + template + class optional + { + public: + using value_type = T; + private: + bool has_value_; + union { + char dummy_; + T value_; + }; + public: + constexpr optional() noexcept + : has_value_(false), dummy_{} + { + } + + // copy constructors + optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + // converting + template ::value && + std::is_constructible::value && + std::is_convertible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_copy_constructible::type>::value,int>::type = 0> + optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + template ::value && + std::is_constructible::value && + !std::is_convertible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_copy_constructible::type>::value,int>::type = 0> + explicit optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + // move constructors + template + optional(optional&& other, + typename std::enable_if::type>::value>::type* = 0) + : has_value_(false), dummy_{} + { + if (other) + { + construct(std::move(other.value_)); + } + } + + // converting + template + optional(optional&& value, + typename std::enable_if::value && + std::is_constructible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + template + explicit optional(optional&& value, + typename std::enable_if::value && + std::is_constructible::value && + !is_constructible_or_convertible_from_optional::value && + !std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + + // value constructors + template + optional(T2&& value, + typename std::enable_if,typename std::decay::type>::value && + std::is_constructible::value && + std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + template + explicit optional(T2&& value, + typename std::enable_if,typename std::decay::type>::value && + std::is_constructible::value && + !std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + ~optional() noexcept + { + destroy(); + } + + optional& operator=(const optional& other) + { + if (other) + { + assign(*other); + } + else + { + reset(); + } + return *this; + } + + optional& operator=(optional&& other ) + { + if (other) + { + assign(std::move(*other)); + } + else + { + reset(); + } + return *this; + } + + template + typename std::enable_if, U>::value && + std::is_constructible::value && + !is_constructible_convertible_or_assignable_from_optional::value && + std::is_assignable::value, + optional&>::type + operator=(const optional& other) + { + if (other) + { + assign(*other); + } + else + { + destroy(); + } + return *this; + } + + template + typename std::enable_if, U>::value && + std::is_constructible::value && + !is_constructible_convertible_or_assignable_from_optional::value && + std::is_assignable::value, + optional&>::type + operator=(optional&& other) + { + if (other) + { + assign(std::move(*other)); + } + else + { + destroy(); + } + return *this; + } + + // value assignment + template + typename std::enable_if, typename std::decay::type>::value && + std::is_constructible::value && + std::is_assignable::value && + !(std::is_scalar::value && std::is_same::type>::value), + optional&>::type + operator=(T2&& v) + { + assign(std::forward(v)); + return *this; + } + + constexpr explicit operator bool() const noexcept + { + return has_value_; + } + constexpr bool has_value() const noexcept + { + return has_value_; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) +#endif // _MSC_VER + + T& value() & + { + return static_cast(*this) + ? get() + : JSONCONS_THROW(std::runtime_error("Bad optional access")), get(); + } + + constexpr const T& value() const & + { + return static_cast(*this) + ? get() + : JSONCONS_THROW(std::runtime_error("Bad optional access")), get(); + } + + template + constexpr T value_or(U&& default_value) const & + { + static_assert(std::is_copy_constructible::value, + "get_value_or: T must be copy constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + return static_cast(*this) + ? **this + : static_cast(std::forward(default_value)); + } + + template + T value_or(U&& default_value) && + { + static_assert(std::is_move_constructible::value, + "get_value_or: T must be move constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + return static_cast(*this) ? std::move(**this) + : static_cast(std::forward(default_value)); + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + + const T* operator->() const + { + return std::addressof(this->value_); + } + + T* operator->() + { + return std::addressof(this->value_); + } + + constexpr const T& operator*() const& + { + return value(); + } + + T& operator*() & + { + return value(); + } + + void reset() noexcept + { + destroy(); + } + + void swap(optional& other) noexcept(std::is_nothrow_move_constructible::value /*&& + std::is_nothrow_swappable::value*/) + { + const bool contains_a_value = has_value(); + if (contains_a_value == other.has_value()) + { + if (contains_a_value) + { + using std::swap; + swap(**this, *other); + } + } + else + { + optional& source = contains_a_value ? *this : other; + optional& target = contains_a_value ? other : *this; + target = optional(*source); + source.reset(); + } + } + private: + constexpr const T& get() const { return this->value_; } + T& get() { return this->value_; } + + template + void construct(Args&&... args) + { + ::new (static_cast(&this->value_)) T(std::forward(args)...); + has_value_ = true; + } + + void destroy() noexcept + { + if (has_value_) + { + value_.~T(); + has_value_ = false; + } + } + + template + void assign(U&& u) + { + if (has_value_) + { + value_ = std::forward(u); + } + else + { + construct(std::forward(u)); + } + } + }; + + template + typename std::enable_if::value,void>::type + swap(optional& lhs, optional& rhs) noexcept + { + lhs.swap(rhs); + } + + template + constexpr bool operator==(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); + } + + template + constexpr bool operator!=(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); + } + + template + constexpr bool operator<(const optional& lhs, const optional& rhs) noexcept + { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); + } + + template + constexpr bool operator>(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); + } + + template + constexpr bool operator<=(const optional& lhs, const optional& rhs) noexcept + { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); + } + + template + constexpr bool operator>=(const optional& lhs, const optional& rhs) noexcept + { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + } + + template + constexpr bool operator==(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs == rhs : false; + } + template + constexpr bool operator==(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs == *rhs : false; + } + + template + constexpr bool operator!=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs != rhs : true; + } + template + constexpr bool operator!=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs != *rhs : true; + } + + template + constexpr bool operator<(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs < rhs : true; + } + template + constexpr bool operator<(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs < *rhs : false; + } + + template + constexpr bool operator<=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs <= rhs : true; + } + template + constexpr bool operator<=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs <= *rhs : false; + } + + template + constexpr bool operator>(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs > rhs : false; + } + + template + constexpr bool operator>(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs > *rhs : true; + } + + template + constexpr bool operator>=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs >= rhs : false; + } + template + constexpr bool operator>=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs >= *rhs : true; + } + +} // namespace detail +} // namespace jsoncons + +#endif -- cgit v1.2.3