// Copyright 2016 Glyn Matthews.
// Copyright (C) 2011 - 2012 Andrzej Krzemienski.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//
http://www.boost.org/LICENSE_1_0.txt)
/**
* \file
* \brief Contains an implementation of C++17 optional (n3793).
*
* \sa
https://github.com/akrzemi1/Optional
* \sa
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html
*/
#ifndef NETWORK_OPTIONAL_INC
#define NETWORK_OPTIONAL_INC
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <memory>
#include <algorithm>
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#ifdef NDEBUG
#define NETWORK_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
#else
#define NETWORK_ASSERTED_EXPRESSION(CHECK, EXPR) \
((CHECK) ? (EXPR) : (fail(#CHECK, __FILE__, __LINE__), (EXPR)))
inline void fail(const char *, const char *, unsigned) {}
#endif // NDEBUG
#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
namespace network {
/**
* \ingroup optional
* \class nullopt_t optional.hpp network/uri.hpp
* \brief Disengaged state indicator.
* \sa optional
*/
struct nullopt_t {
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
struct init {};
constexpr nullopt_t(init) {}
#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
};
/**
* \ingroup optional
* \brief Used to indicate a *disengaged* state for optional objects.
*/
constexpr nullopt_t nullopt{nullopt_t::init{}};
/**
* \ingroup optional
* \class bad_optional_access optional.hpp network/uri.hpp
* \brief Exception thrown when the value member function is called when the
* optional object is disengaged.
*/
class bad_optional_access : public std::logic_error {
public:
/**
* \brief Constructor.
* \param what_arg The error message.
*/
explicit bad_optional_access(const std::string &what_arg)
: std::logic_error(what_arg) {}
/**
* \brief Constructor.
* \param what_arg The error message.
*/
explicit bad_optional_access(const char *what_arg)
: std::logic_error(what_arg) {}
};
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
namespace details {
struct dummy_t {};
template <class T>
union trivially_destructible_optional_storage {
static_assert(std::is_trivially_destructible<T>::value, "");
dummy_t dummy_;
T value_;
constexpr trivially_destructible_optional_storage() : dummy_{} {}
constexpr trivially_destructible_optional_storage(const T &v) : value_{v} {}
~trivially_destructible_optional_storage() = default;
};
template <class T>
union optional_storage {
dummy_t dummy_;
T value_;
constexpr optional_storage() : dummy_{} {}
constexpr optional_storage(const T &v) : value_{v} {}
~optional_storage() {}
};
template <class T>
class trivially_destructible_optional_base {
public:
typedef T value_type;
constexpr trivially_destructible_optional_base() noexcept
: init_(false), storage_{} {}
constexpr trivially_destructible_optional_base(const T &v)
: init_(true), storage_{v} {}
constexpr trivially_destructible_optional_base(T &&v)
: init_(true), storage_{std::move(v)} {}
~trivially_destructible_optional_base() = default;
protected:
bool init_;
optional_storage<T> storage_;
};
template <class T>
class optional_base {
public:
typedef T value_type;
constexpr optional_base() noexcept : init_(false), storage_{} {}
constexpr optional_base(const T &v) : init_(true), storage_{v} {}
constexpr optional_base(T &&v) : init_(true), storage_{std::move(v)} {}
~optional_base() {
if (init_) {
storage_.value_.T::~T();
}
}
protected:
bool init_;
optional_storage<T> storage_;
};
} // namespace details
#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
/**
* \ingroup optional
* \class optional optional.hpp network/uri.hpp
* \brief An implementation of C++17 optional (n3793)
*/
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
template <class T>
using optional_base =
typename std::conditional<std::is_trivially_destructible<T>::value,
details::trivially_destructible_optional_base<T>,
details::optional_base<T>>::type;
#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
template <class T>
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
class optional : optional_base<T> {
#else
class optional {
#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
typedef optional_base<T> base_type;
public:
/**
* \brief Optional value type.
*/
typedef T value_type;
/**
* \brief Constructor.
* \post *disengaged*.
*/
constexpr optional() : optional_base<T>() {}
/**
* \brief Constructor.
* \post *disengaged*.
*/
constexpr optional(nullopt_t) noexcept : optional_base<T>() {}
/**
* \brief Copy constructor.
* \param other The other optional object.
*/
optional(const optional &other) {
if (other) {
::new (static_cast<void *>(ptr())) T(*other);
base_type::init_ = true;
}
}
/**
* \brief Move constructor.
* \param other The other optional object.
*/
optional(optional &&other) noexcept {
if (other) {
::new (static_cast<void *>(ptr())) T(std::move(other.storage_.value_));
base_type::init_ = true;
}
}
/**
* \brief Constructor.
* \param value The value with which to initialize the optional object.
* \post *engaged*
*/
constexpr optional(const T &value) : optional_base<T>(value) {}
/**
* \brief Constructor.
* \param value The value with which to initialize the optional object.
* \post *engaged*
*/
constexpr optional(T &&value) : optional_base<T>(std::move(value)) {}
/**
* \brief Assignment operator.
* \post *disengaged*.
* \returns \c *this.
*/
optional &operator=(nullopt_t) noexcept {
if (base_type::init_) {
ptr()->T::~T();
}
base_type::init_ = false;
return *this;
}
/**
* \brief Copy assignment operator.
* \param other The other optional object.
* \returns \c *this.
*/
optional &operator=(const optional &other) {
if (bool(*this) && !other) {
ptr()->T::~T();
base_type::init_ = false;
} else if (!(*this) && bool(other)) {
::new (static_cast<void *>(ptr())) T(*other);
base_type::init_ = true;
} else if (bool(*this) && bool(other)) {
base_type::storage_.value_ = *other;
}
return *this;
}
/**
* \brief Move assignment operator.
* \param other The other optional object.
* \returns \c *this.
*/
optional &operator=(optional &&other) noexcept {
if (bool(*this) && !other) {
ptr()->T::~T();
base_type::init_ = false;
} else if (!(*this) && bool(other)) {
::new (static_cast<void *>(ptr())) T(std::move(*other));
base_type::init_ = true;
} else if (bool(*this) && bool(other)) {
base_type::storage_.value_ = std::move(*other);
}
return *this;
}
/**
* \brief Destructor.
*/
~optional() = default;
/**
* \brief Swap function.
* \param other The other optional object.
*/
void swap(optional &other) noexcept {
if (bool(*this) && !other) {
::new (static_cast<void *>(other.ptr())) T(std::move(**this));
ptr()->T::~T();
std::swap(base_type::init_, other.base_type::init_);
} else if (!(*this) && bool(other)) {
::new (static_cast<void *>(ptr())) T(std::move(*other));
other.ptr()->T::~T();
std::swap(base_type::init_, other.init_);
} else if (bool(*this) && bool(other)) {
std::swap(**this, *other);
}
}
/**
* \brief Observer.
* \pre *engaged*
* \returns The underlying optional value.
*/
constexpr T const *operator->() const {
return NETWORK_ASSERTED_EXPRESSION(bool(*this), ptr());
}
/**
* \brief Observer.
* \pre *engaged*
* \returns The underlying optional value.
*/
T *operator->() { return NETWORK_ASSERTED_EXPRESSION(bool(*this), ptr()); }
/**
* \brief Observer.
* \pre *engaged*
* \returns The underlying optional value.
*/
constexpr T const &operator*() const {
return NETWORK_ASSERTED_EXPRESSION(bool(*this), base_type::storage_.value_);
}
/**
* \brief Observer.
* \pre *engaged*
* \returns The underlying optional value.
*/
T &operator*() {
return NETWORK_ASSERTED_EXPRESSION(bool(*this), base_type::storage_.value_);
}
/**
* \brief Operator bool overloads.
* \returns \c true if the optional is *engaged*, \c false if it is
* *disengaged*.
*/
constexpr explicit operator bool() const noexcept { return base_type::init_; }
/**
* \returns The underlying optional value, if \c bool(*this).
* \throws A bad_optional_access if \c !*this.
*/
constexpr T const &value() const {
return *this ? base_type::storage_.value_
: (throw bad_optional_access("Uninitialized optional value"),
base_type::storage_.value_);
}
/**
* \returns The underlying optional value, if \c bool(*this).
* \throws A bad_optional_access if \c !*this.
*/
T &value() {
return *this ? base_type::storage_.value_
: (throw bad_optional_access("Uninitialized optional value"),
base_type::storage_.value_);
}
/**
* \returns <tt>bool(*this) ? **this :
* static_cast<T>(std::forward<U>(v))</tt>. \pre \c
* <tt>std::is_copy_constructible<T>::value</tt> is \c true and
* <tt>std::is_convertible<U&&, T>::value</tt> is \c true.
*/
template <class U>
T value_or(U &&other) const & {
static_assert(std::is_copy_constructible<value_type>::value,
"Must be copy constructible.");
static_assert(std::is_convertible<U, value_type>::value,
"U must be convertible to T.");
return bool(*this) ? **this : static_cast<T>(std::forward<U>(other));
}
/**
* \returns <tt>bool(*this) ? std::move(**this) :
* static_cast<T>(std::forward<U>(v))</tt>. \pre
* <tt>std::is_move_constructible<T>::value</tt> is \c true and
* <tt>std::is_convertible<U&&, T>::value</tt> is \c true.
*/
template <class U>
T value_or(U &&other) && {
static_assert(std::is_copy_constructible<value_type>::value,
"Must be copy constructible.");
static_assert(std::is_convertible<U, value_type>::value,
"U must be convertible to T.");
return bool(*this) ? std::move(**this)
: static_cast<T>(std::forward<U>(other));
}
private:
T *ptr() { return std::addressof(base_type::storage_.value_); }
};
/**
* \brief Equality operator.
*/
template <class T>
bool operator==(const optional<T> &lhs, const optional<T> &rhs) {
if (bool(lhs) != bool(rhs)) {
return false;
} else if (!bool(lhs)) {
return true;
} else {
return *lhs == *rhs;
}
}
/**
* \brief Inequality operator.
*/
template <class T>
bool operator!=(const optional<T> &lhs, const optional<T> &rhs) {
return !(lhs == rhs);
}
/**
* \brief Comparison operator.
*/
template <class T>
bool operator<(const optional<T> &lhs, const optional<T> &rhs) {
if (!rhs) {
return false;
} else if (!lhs) {
return true;
} else {
return *lhs < *rhs;
}
}
/**
* \brief Comparison operator.
* \returns <tt>rhs < lhs</tt>.
*/
template <class T>
bool operator>(const optional<T> &lhs, const optional<T> &rhs) {
return rhs < lhs;
}
/**
* \brief Comparison operator.
* \returns <tt>!(rhs < lhs)</tt>.
*/
template <class T>
bool operator<=(const optional<T> &lhs, const optional<T> &rhs) {
return !(rhs < lhs);
}
/**
* \brief Comparison operator.
* \returns <tt>!(rhs > lhs)</tt>.
*/
template <class T>
bool operator>=(const optional<T> &lhs, const optional<T> &rhs) {
return !(lhs < rhs);
}
/**
* \brief Equality operator.
* \returns \c !x.
*/
template <class T>
bool operator==(const optional<T> &x, nullopt_t) noexcept {
return !x;
}
/**
* \brief Equality operator.
* \returns \c !x.
*/
template <class T>
bool operator==(nullopt_t, const optional<T> &x) noexcept {
return !x;
}
/**
* \brief Inequality operator.
* \returns \c bool(x).
*/
template <class T>
bool operator!=(const optional<T> &x, nullopt_t) noexcept {
return bool(x);
}
/**
* \brief Inequality operator.
* \returns \c bool(x).
*/
template <class T>
bool operator!=(nullopt_t, const optional<T> &x) noexcept {
return bool(x);
}
/**
* \brief Comparison operator.
* \returns \c false.
*/
template <class T>
bool operator<(const optional<T> &x, nullopt_t) noexcept {
return false;
}
/**
* \brief Comparison operator.
* \returns \c bool(x).
*/
template <class T>
bool operator<(nullopt_t, const optional<T> &x) noexcept {
return bool(x);
}
/**
* \brief Comparison operator.
* \returns \c !x.
*/
template <class T>
bool operator<=(const optional<T> &x, nullopt_t) noexcept {
return !x;
}
/**
* \brief Comparison operator.
* \returns \c true.
*/
template <class T>
bool operator<=(nullopt_t, const optional<T> &x) noexcept {
return true;
}
/**
* \brief Comparison operator.
* \returns \c bool(x).
*/
template <class T>
bool operator>(const optional<T> &x, nullopt_t) noexcept {
return bool(x);
}
/**
* \brief Comparison operator.
* \returns \c false.
*/
template <class T>
bool operator>(nullopt_t, const optional<T> &x) noexcept {
return false;
}
/**
* \brief Comparison operator.
* \returns \c true.
*/
template <class T>
bool operator>=(const optional<T> &x, nullopt_t) noexcept {
return true;
}
/**
* \brief Comparison operator.
* \returns \c !x.
*/
template <class T>
bool operator>=(nullopt_t, const optional<T> &x) noexcept {
return !x;
}
/**
* \brief Equality operator.
* \returns <tt>bool(x) ? *x == v : false</tt>.
*/
template <class T>
bool operator==(const optional<T> &x, const T &v) {
return bool(x) ? *x == v : false;
}
/**
* \brief Equality operator.
* \returns <tt>bool(x) ? v == *x : false</tt>.
*/
template <class T>
bool operator==(const T &v, const optional<T> &x) {
return bool(x) ? v == *x : false;
}
/**
* \brief Inequality operator.
* \returns <tt>bool(x) ? !(*x == v) : true</tt>.
*/
template <class T>
bool operator!=(const optional<T> &x, const T &v) {
return bool(x) ? !(*x == v) : true;
}
/**
* \brief Inequality operator.
* \returns <tt>bool(x) ? !(v == *x) : true</tt>.
*/
template <class T>
bool operator!=(const T &v, const optional<T> &x) {
return bool(x) ? !(v == *x) : true;
}
/**
* \brief Comparison operator.
* \returns <tt>bool(x) ? *x < v : true</tt>.
*/
template <class T>
bool operator<(const optional<T> &x, const T &v) {
return bool(x) ? *x < v : true;
}
/**
* \brief Comparison operator.
* \returns <tt>bool(x) ? v < *x : false</tt>.
*/
template <class T>
bool operator<(const T &v, const optional<T> &x) {
return bool(x) ? v < *x : false;
}
/**
* \brief Comparison operator.
* \returns <tt>bool(x) ? *x < v : true</tt>.
*/
template <class T>
bool operator>(const optional<T> &x, const T &v) {
return bool(x) ? *x < v : true;
}
/**
* \brief Comparison operator.
* \returns <tt>bool(x) ? v < *x : false</tt>.
*/
template <class T>
bool operator>(const T &v, const optional<T> &x) {
return bool(x) ? v < *x : false;
}
/**
* \brief Comparison operator.
* \returns <tt>!(x < v)</tt>.
*/
template <class T>
bool operator>=(const optional<T> &x, const T &v) {
return !(x < v);
}
/**
* \brief Comparison operator.
* \returns <tt>!(v < x)</tt>.
*/
template <class T>
bool operator>=(const T &v, const optional<T> &x) {
return !(v < x);
}
/**
* \brief Comparison operator.
* \returns <tt>!(x > v)</tt>.
*/
template <class T>
bool operator<=(const optional<T> &x, const T &v) {
return !(x > v);
}
/**
* \brief Comparison operator.
* \returns <tt>!(v > x)</tt>.
*/
template <class T>
bool operator<=(const T &v, const optional<T> &x) {
return !(v > x);
}
/**
* \ingroup optional
* \brief Swap function.
* \param lhs The first optional object.
* \param rhs The second optional object.
*
* Calls:
* \code{.cpp}
* lhs.swap(rhs);
* \endcode
*/
template <class T>
inline void swap(optional<T> &lhs,
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
return lhs.swap(rhs);
}
/**
* \ingroup optional
* \brief A helper function to contruct an optional object.
* \returns <tt>optional<typename
* std::decay<T>::type>(std::forward(value))</tt>.
*/
template <class T>
inline constexpr optional<typename std::decay<T>::type> make_optional(
T &&value) {
return optional<typename std::decay<T>::type>(std::forward(value));
}
} // namespace network
#endif // NETWORK_OPTIONAL_INC