citrus/include/bpstd/optional.hpp
Robert Sebastian Herlim e27ed026dd Initial commit of CITRUS
2021-10-04 10:56:53 +09:00

1780 lines
58 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// \file optional.hpp
///
/// \brief This header provides definitions from the C++ header <optional>
////////////////////////////////////////////////////////////////////////////////
/*
The MIT License (MIT)
Copyright (c) 2020 Matthew Rodusek All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef BPSTD_OPTIONAL_HPP
#define BPSTD_OPTIONAL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "detail/config.hpp"
#include "detail/enable_overload.hpp" // enable_overload_if, disable_overload_if
#include "utility.hpp" // in_place_t, forward, move
#include "functional.hpp" // invoke_result_t
#include "type_traits.hpp"
#include <initializer_list> // std::initializer_list
#include <type_traits> // enable_if
#include <stdexcept> // std::logic_error
#include <new> // placement new
#include <cassert>
BPSTD_COMPILER_DIAGNOSTIC_PREAMBLE
namespace bpstd {
template <typename> class optional;
namespace detail {
//==========================================================================
// trait : is_optional
//==========================================================================
template <typename T, typename U>
using optional_is_convertible = conjunction<
std::is_constructible<T, optional<U>&>,
std::is_constructible<T, const optional<U>&>,
std::is_constructible<T, optional<U>&&>,
std::is_constructible<T, const optional<U>&&>,
std::is_convertible<optional<U>&, T>,
std::is_convertible<const optional<U>&, T>,
std::is_convertible<optional<U>&&, T>,
std::is_convertible<const optional<U>&&, T>
>;
template <typename T, typename U>
using optional_is_copy_convertible = conjunction<
optional_is_convertible<T,U>,
std::is_constructible<T, const U&>
>;
template <typename T, typename U>
using optional_is_move_convertible = conjunction<
optional_is_convertible<T,U>,
std::is_constructible<T, U&&>
>;
template <typename T, typename U>
using optional_is_value_convertible = conjunction<
std::is_constructible<T, U&&>,
negation<std::is_same<decay_t<U>,in_place_t>>,
negation<std::is_same<decay_t<U>,optional<T>>>
>;
template <typename T, typename U>
using optional_is_convert_assignable = conjunction<
optional_is_convertible<T,U>,
std::is_assignable<T&, optional<U>&>,
std::is_assignable<T&, const optional<U>&>,
std::is_assignable<T&, optional<U>&&>,
std::is_assignable<T&, const optional<U>&&>
>;
template <typename T, typename U>
using optional_is_copy_convert_assignable = conjunction<
optional_is_convert_assignable<T,U>,
std::is_constructible<T, const U&>,
std::is_assignable<T&, const U&>
>;
template <typename T, typename U>
using optional_is_move_convert_assignable = conjunction<
optional_is_convert_assignable<T,U>,
std::is_constructible<T, U&&>,
std::is_assignable<T&, U&&>
>;
template <typename T, typename U>
using optional_is_value_assignable = conjunction<
negation<std::is_same<decay_t<U>,optional<T>>>,
std::is_constructible<T,U>,
std::is_assignable<T,U>,
disjunction<
negation<std::is_same<decay_t<U>,T>>,
negation<std::is_scalar<T>>
>
>;
} // namespace detail
//=========================================================================
// class : bad_optional_access
//=========================================================================
///////////////////////////////////////////////////////////////////////////
/// \brief An exception thrown when an optional is attempted to be accessed
/// while not containing a value
///////////////////////////////////////////////////////////////////////////
class bad_optional_access : public std::logic_error
{
public:
bad_optional_access() : std::logic_error("bad_optional_access"){}
};
//=========================================================================
// struct : nullopt_t
//=========================================================================
/// \brief This type represents null optional value
struct nullopt_t
{
nullopt_t() = delete;
constexpr explicit nullopt_t(int) noexcept{}
};
//-------------------------------------------------------------------------
/// \brief Instance of a nullopt type
constexpr nullopt_t nullopt = nullopt_t{0};
//=========================================================================
// class : optional
//=========================================================================
namespace detail {
template <typename T, bool IsTrivial> class optional_base;
template <typename T>
class optional_base<T,true>
{
//---------------------------------------------------------------------
// Constructors / Assignment
//---------------------------------------------------------------------
public:
// cppcheck-suppress noExplicitConstructor
constexpr optional_base(nullopt_t) noexcept;
template <typename...Args>
constexpr optional_base(in_place_t, Args&&...args)
noexcept(std::is_nothrow_constructible<T,Args...>::value);
optional_base(optional_base&& other) = default;
optional_base(const optional_base& other) = default;
//---------------------------------------------------------------------
optional_base& operator=(optional_base&& other) = default;
optional_base& operator=(const optional_base& other) = default;
//---------------------------------------------------------------------
// Protected Modifiers
//---------------------------------------------------------------------
protected:
BPSTD_CPP14_CONSTEXPR T* val() noexcept;
constexpr const T* val() const noexcept;
constexpr bool contains_value() const noexcept;
//---------------------------------------------------------------------
// Protected Observers
//---------------------------------------------------------------------
protected:
template <typename...Args>
void construct(Args&&...args);
void destruct();
//---------------------------------------------------------------------
// Private Member Types
//---------------------------------------------------------------------
private:
struct empty{};
union storage_type {
empty nothing;
T something;
template <typename...Args>
constexpr storage_type(in_place_t, Args&&...args)
: something(bpstd::forward<Args>(args)...){}
constexpr storage_type() : nothing(){}
};
//---------------------------------------------------------------------
// Private Members
//---------------------------------------------------------------------
private:
storage_type m_storage;
bool m_engaged;
};
template <typename T>
class optional_base<T,false>
{
//---------------------------------------------------------------------
// Protected Constructors / Destructor / Assignment
//---------------------------------------------------------------------
protected:
// cppcheck-suppress noExplicitConstructor
optional_base(nullopt_t) noexcept;
template <typename...Args>
optional_base(in_place_t, Args&&...args)
noexcept(std::is_nothrow_constructible<T,Args...>::value);
optional_base(optional_base&& other) = default;
optional_base(const optional_base& other) = default;
//---------------------------------------------------------------------
~optional_base() noexcept(std::is_nothrow_destructible<T>::value);
//---------------------------------------------------------------------
optional_base& operator=(optional_base&& other) = default;
optional_base& operator=(const optional_base& other) = default;
//---------------------------------------------------------------------
// Protected Observers
//---------------------------------------------------------------------
protected:
T* val() noexcept;
const T* val() const noexcept;
bool contains_value() const noexcept;
//---------------------------------------------------------------------
// Protected Modifiers
//---------------------------------------------------------------------
protected:
template <typename...Args>
void construct(Args&&...args);
void destruct();
//---------------------------------------------------------------------
// Private Member Types
//---------------------------------------------------------------------
private:
struct empty{};
union storage_type {
empty nothing;
T something;
template <typename...Args>
storage_type(in_place_t, Args&&...args)
: something(bpstd::forward<Args>(args)...){}
storage_type() : nothing(){}
~storage_type(){}
};
//---------------------------------------------------------------------
// Private Members
//---------------------------------------------------------------------
private:
storage_type m_storage;
bool m_engaged;
};
} // namespace detail
///////////////////////////////////////////////////////////////////////////
/// \brief The class template optional manages an optional contained value,
/// i.e. a value that may or may not be present.
///
/// A common use case for optional is the return value of a function that
/// may fail. As opposed to other approaches, such as std::pair<T,bool>,
/// optional handles expensive to construct objects well and is more
/// readable, as the intent is expressed explicitly.
///
/// Any instance of optional<T> at any given point in time either contains
/// a value or does not contain a value.
///
/// If an optional<T> contains a value, the value is guaranteed to be
/// allocated as part of the optional object footprint, i.e. no dynamic
/// memory allocation ever takes place. Thus, an optional object models an
/// object, not a pointer, even though the operator*() and operator->()
/// are defined.
///
/// When an object of type optional<T> is contextually converted to bool,
/// the conversion returns true if the object contains a value and false if
/// it does not contain a value.
///
/// The optional object contains a value in the following conditions:
/// - The object is initialized with a value of type T
/// - The object is assigned from another optional that contains a value.
/// - The object does not contain a value in the following conditions:
/// - The object is default-initialized.
/// - The object is initialized with a value of nullopt_t or an optional
/// object that does not contain a value.
/// - The object is assigned from a value of nullopt_t or from an optional
/// that does not contain a value
///
/// \tparam T the underlying type
///////////////////////////////////////////////////////////////////////////
template <typename T>
class optional
: detail::optional_base<T,std::is_trivially_destructible<T>::value>
{
static_assert(
!std::is_void<T>::value,
"optional<void> is ill-formed"
);
static_assert(
!std::is_reference<T>::value,
"optional<T> is ill-formed"
);
static_assert(
!std::is_abstract<T>::value,
"optional of an abstract-type is ill-formed"
);
using base_type = detail::optional_base<T,std::is_trivially_destructible<T>::value>;
//-----------------------------------------------------------------------
// Public Member Types
//-----------------------------------------------------------------------
public:
using value_type = T; ///< The underlying type of this Optional
//-----------------------------------------------------------------------
// Constructor / Destructor / Assignment
//-----------------------------------------------------------------------
public:
/// \{
/// \brief Constructs an optional that does not contain a value
constexpr optional() noexcept;
// cppcheck-suppress noExplicitConstructor
constexpr optional(nullopt_t) noexcept;
/// \}
/// \brief Copy constructs an optional
///
/// If \p other contains a value, initializes the contained value as if
/// direct-initializing (but not direct-list-initializing) an object of
/// type T with the expression *other.
///
/// If other does not contain a value, constructs an object that does
/// not contain a value.
///
/// \note This constructor is defined as deleted if std::is_copy_constructible_v<T> is false
///
/// \param other the optional to copy
// cppcheck-suppress noExplicitConstructor
optional(detail::enable_overload_if_t<std::is_copy_constructible<T>::value,const optional&> other);
optional(detail::disable_overload_if_t<std::is_copy_constructible<T>::value,const optional&> other) = delete;
/// \brief Move constructs an optional
///
/// If other contains a value, initializes the contained value as if
/// direct-initializing (but not direct-list-initializing) an object
/// of type T with the expression std::move(*other) and does not make
/// other empty: a moved-from optional still contains a value, but the
/// value itself is moved from.
///
/// If other does not contain a value, constructs an object that does
/// not contain a value.
///
/// \note This constructor is defined as deleted if std::is_move_constructible_v<T> is false
///
/// \param other the optional to move
// cppcheck-suppress noExplicitConstructor
optional(detail::enable_overload_if_t<std::is_move_constructible<T>::value,optional&&> other);
optional(detail::disable_overload_if_t<std::is_move_constructible<T>::value,optional&&> other) = delete;
/// \{
/// \brief Converting copy constructor
///
/// If other doesn't contain a value, constructs an optional object
/// that does not contain a value. Otherwise, constructs an optional
/// object that contains a value, initialized as if direct-initializing
/// (but not direct-list-initializing) an object of type T with the
/// expression *other.
///
/// \note This constructor does not participate in overload resolution
/// unless the following conditions are met:
/// - std::is_constructible_v<T, const U&> is true
/// - T is not constructible or convertible from any expression
/// of type (possibly const) optional<U>, i.e., the
/// following 8 type traits are all false:
/// - std::is_constructible_v<T, std::optional<U>&>
/// - std::is_constructible_v<T, const std::optional<U>&>
/// - std::is_constructible_v<T, std::optional<U>&&>
/// - std::is_constructible_v<T, const std::optional<U>&&>
/// - std::is_convertible_v<std::optional<U>&, T>
/// - std::is_convertible_v<const std::optional<U>&, T>
/// - std::is_convertible_v<std::optional<U>&&, T>
/// - std::is_convertible_v<const std::optional<U>&&, T>
///
/// \note This constructor is explicit if and only if
/// std::is_convertible_v<const U&, T> is false
///
/// \param other the other type to convert
template <typename U,
enable_if_t<detail::optional_is_copy_convertible<T,U>::value && std::is_convertible<const U&, T>::value>* =nullptr>
// cppcheck-suppress noExplicitConstructor
optional(const optional<U>& other);
template <typename U,
enable_if_t<detail::optional_is_copy_convertible<T,U>::value && !std::is_convertible<const U&, T>::value>* =nullptr>
explicit optional(const optional<U>& other);
/// \}
/// \{
/// \brief Converting move constructor
///
/// If other doesn't contain a value, constructs an optional object
/// that does not contain a value. Otherwise, constructs an optional
/// object that contains a value, initialized as if direct-initializing
/// (but not direct-list-initializing) an object of type T with the
/// expression std::move(*other).
///
/// \note This constructor does not participate in overload resolution
/// unless the following conditions are met:
/// - std::is_constructible_v<T, U&&> is true
/// - T is not constructible or convertible from any expression
/// of type (possibly const) optional<U>, i.e., the
/// following 8 type traits are all false:
/// - std::is_constructible_v<T, std::optional<U>&>
/// - std::is_constructible_v<T, const std::optional<U>&>
/// - std::is_constructible_v<T, std::optional<U>&&>
/// - std::is_constructible_v<T, const std::optional<U>&&>
/// - std::is_convertible_v<std::optional<U>&, T>
/// - std::is_convertible_v<const std::optional<U>&, T>
/// - std::is_convertible_v<std::optional<U>&&, T>
/// - std::is_convertible_v<const std::optional<U>&&, T>
///
/// \note This constructor is explicit if and only if
/// std::is_convertible_v<U&&, T> is false
///
/// \param other the other optional to move
template <typename U,
enable_if_t<detail::optional_is_move_convertible<T,U>::value && std::is_convertible<U&&, T>::value>* =nullptr>
// cppcheck-suppress noExplicitConstructor
optional(optional<U>&& other);
template <typename U,
enable_if_t<detail::optional_is_move_convertible<T,U>::value && !std::is_convertible<U&&, T>::value>* =nullptr>
explicit optional(optional<U>&& other);
/// \}
/// \brief Constructs an optional object that contains a value
///
/// the value is initialized as if direct-initializing (but not
/// direct-list-initializing) an object of type T from the arguments
/// std::forward<Args>(args)...
///
/// \param args the arguments to pass to T's constructor
template <typename...Args,
typename=enable_if_t<std::is_constructible<T,Args...>::value>>
constexpr explicit optional(in_place_t, Args&&... args);
/// \brief Constructs an optional object that contains a value
///
/// The value is initialized as if direct-initializing (but not
/// direct-list-initializing) an object of type T from the arguments
/// std::forward<std::initializer_list<U>>(ilist), std::forward<Args>(args)...
///
/// \param ilist An initializer list of entries to forward
/// \param args the arguments to pass to T's constructor
template <typename U, typename...Args,
typename=enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args...>::value>>
constexpr explicit optional(in_place_t,
std::initializer_list<U> ilist,
Args&&...args);
/// \{
/// \brief Constructs an optional object that contains a value
///
/// The value is initialized as if direct-initializing (but not
/// direct-list-initializing) an object of type T with the expression
/// value.
///
/// \note This constructor is constexpr if the constructor of T
/// selected by direct-initialization is constexpr
///
/// \note This constructor does not participate in overload
/// resolution unless std::is_constructible_v<T, U&&> is true
/// and decay_t<U> is neither std::in_place_t nor
/// optional<T>.
///
/// \note This constructor is explicit if and only if
/// std::is_convertible_v<U&&, T> is false
///
/// \param value the value to copy
template <typename U=T,
enable_if_t<detail::optional_is_value_convertible<T,U>::value && std::is_convertible<U&&, T>::value>* =nullptr>
// cppcheck-suppress noExplicitConstructor
constexpr optional(U&& value);
template <typename U=T,
enable_if_t<detail::optional_is_value_convertible<T,U>::value && !std::is_convertible<U&&, T>::value>* =nullptr>
constexpr explicit optional(U&& value);
/// \}
//-----------------------------------------------------------------------
/// \brief Assigns this optional to be a null optional
///
/// If \c (*this) had a value before the call, the contained value is
/// destroyed.
optional& operator=(nullopt_t);
/// \brief Copy assigns the optional stored in \p other
///
/// \param other the other optional to copy
optional& operator=(detail::enable_overload_if_t<std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,const optional&> other);
optional& operator=(detail::disable_overload_if_t<std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,const optional&> other) = delete;
/// \brief Move assigns the optional stored in \p other
///
/// \note If \p other contained a value before the call, it is left as a
/// null optional
///
/// \remark This assignment does not participate in overload resolution
/// unless U is
///
/// \param other the other optional to move
optional& operator=(detail::enable_overload_if_t<std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,optional&&> other);
optional& operator=(detail::disable_overload_if_t<std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,optional&&> other) = delete;
/// \brief Perfect-forwarded assignment
///
/// Depending on whether *this contains a value before the call, the
/// contained value is either direct-initialized from std::forward<U>(value)
/// or assigned from std::forward<U>(value).
///
/// \note The function does not participate in overload resolution unless
/// - decay_t<U> is not optional<T>,
/// - std::is_constructible_v<T, U> is true
/// - std::is_assignable_v<T&, U> is true
/// - and at least one of the following is true:
/// - T is not a scalar type;
/// - decay_t<U> is not T.
///
/// \param value to assign to the contained value
/// \return reference to \c (*this)
template <typename U=T,
typename=enable_if_t<detail::optional_is_value_assignable<T,U>::value>>
optional& operator=(U&& value);
/// \brief Assigns the state of \p other
///
/// If both *this and other do not contain a value, the function has no effect.
///
/// If *this contains a value, but other does not, then the contained
/// value is destroyed by calling its destructor. *this does not
/// contain a value after the call.
///
/// If other contains a value, then depending on whether *this contains a value,
/// the contained value is either direct-initialized or assigned from *other.
///
/// \note A moved-from optional still contains a value.
///
/// \note This overload does not participate in overload resolution unless the
/// following conditions are met:
/// - std::is_constructible_v<T, const U&> and
/// std::is_assignable_v<T&, const U&> are both true.
/// - T is not constructible, convertible, or assignable from any expression
/// of type (possibly const) :optional<U>, i.e.,
/// the following 12 type traits are all false:
/// - std::is_constructible_v<T, std::optional<U>&>
/// - std::is_constructible_v<T, const std::optional<U>&>
/// - std::is_constructible_v<T, std::optional<U>&&>
/// - std::is_constructible_v<T, const std::optional<U>&&>
/// - std::is_convertible_v<std::optional<U>&, T>
/// - std::is_convertible_v<const std::optional<U>&, T>
/// - std::is_convertible_v<std::optional<U>&&, T>
/// - std::is_convertible_v<const std::optional<U>&&, T>
/// - std::is_assignable_v<T&, std::optional<U>&>
/// - std::is_assignable_v<T&, const std::optional<U>&>
/// - std::is_assignable_v<T&, std::optional<U>&&>
/// - std::is_assignable_v<T&, const std::optional<U>&&>.
///
/// \param other another optional object whose contained value to assign
/// \return reference to (*this)
template <typename U>
optional& operator=(enable_if_t<detail::optional_is_copy_convert_assignable<T,U>::value,const optional<U>&> other);
/// \brief Assigns the state of \p other
///
/// If both *this and other do not contain a value, the function has no effect.
///
/// If *this contains a value, but other does not, then the contained
/// value is destroyed by calling its destructor. *this does not
/// contain a value after the call.
///
/// If other contains a value, then depending on whether *this contains a value,
/// the contained value is either direct-initialized or assigned from
/// std::move(*other).
///
/// \note A moved-from optional still contains a value.
///
/// \note This overload does not participate in overload resolution unless the
/// following conditions are met:
/// - std::is_constructible_v<T, U&&> and
/// std::is_assignable_v<T&, U&&> are both true.
/// - T is not constructible, convertible, or assignable from any expression
/// of type (possibly const) :optional<U>, i.e.,
/// the following 12 type traits are all false:
/// - std::is_constructible_v<T, std::optional<U>&>
/// - std::is_constructible_v<T, const std::optional<U>&>
/// - std::is_constructible_v<T, std::optional<U>&&>
/// - std::is_constructible_v<T, const std::optional<U>&&>
/// - std::is_convertible_v<std::optional<U>&, T>
/// - std::is_convertible_v<const std::optional<U>&, T>
/// - std::is_convertible_v<std::optional<U>&&, T>
/// - std::is_convertible_v<const std::optional<U>&&, T>
/// - std::is_assignable_v<T&, std::optional<U>&>
/// - std::is_assignable_v<T&, const std::optional<U>&>
/// - std::is_assignable_v<T&, std::optional<U>&&>
/// - std::is_assignable_v<T&, const std::optional<U>&&>.
///
/// \param other another optional object whose contained value to assign
/// \return reference to (*this)
template <typename U>
optional& operator=(enable_if_t<detail::optional_is_move_convert_assignable<T,U>::value,optional<U>&&> other);
//-----------------------------------------------------------------------
// Observers
//-----------------------------------------------------------------------
/// \{
/// \brief Accesses the contained value
///
/// \note The behavior is undefined if \c *this does not contain a value.
///
/// \return a pointer to the contained value
BPSTD_CPP14_CONSTEXPR value_type* operator->() noexcept;
constexpr const value_type* operator->() const noexcept;
/// \}
/// \{
/// \brief Accesses the contained value
///
/// \note The behaviour is undefined if \c *this does not contain a value
///
/// \return a reference to the contained value
BPSTD_CPP14_CONSTEXPR value_type& operator*() & noexcept;
BPSTD_CPP14_CONSTEXPR value_type&& operator*() && noexcept;
constexpr const value_type& operator*() const& noexcept;
constexpr const value_type&& operator*() const&& noexcept;
/// \}
/// \brief Checks whether \c *this contains a value
///
/// \return \c true if \c *this contains a value, \c false if \c *this
/// does not contain a value
constexpr explicit operator bool() const noexcept;
/// \brief Checks whether \c *this contains a value
///
/// \return \c true if \c *this contains a value, \c false if \c *this
/// does not contain a value
constexpr bool has_value() const noexcept;
//-----------------------------------------------------------------------
/// \{
/// \brief Returns the contained value.
///
/// \throws bad_optional_access if \c *this does not contain a value.
///
/// \return the value of \c *this
BPSTD_CPP14_CONSTEXPR value_type& value() &;
BPSTD_CPP14_CONSTEXPR value_type&& value() &&;
/// \}
/// \{
/// \brief Returns the contained value.
///
/// \throws bad_optional_access if \c *this does not contain a value.
///
/// \return the value of \c *this
BPSTD_CPP14_CONSTEXPR const value_type& value() const &;
BPSTD_CPP14_CONSTEXPR const value_type&& value() const &&;
/// \}
//-----------------------------------------------------------------------
/// \{
/// \brief Returns the contained value if \c *this has a value,
/// otherwise returns \p default_value.
///
/// \param default_value the value to use in case \c *this is empty
/// \return the value to use in case \c *this is empty
template <typename U>
constexpr value_type value_or(U&& default_value) const &;
template <typename U>
BPSTD_CPP14_CONSTEXPR value_type value_or(U&& default_value) &&;
/// \}
//-----------------------------------------------------------------------
// Modifiers
//-----------------------------------------------------------------------
/// \brief Swaps the contents with those of other.
///
/// \param other the optional object to exchange the contents with
void swap(optional& other);
/// \brief If \c *this contains a value, destroy that value as if by
/// \c value().T::~T().
///
/// Otherwise, there are no effects. \c *this does not contain a value
/// after this call.
void reset() noexcept(std::is_nothrow_destructible<T>::value);
/// \brief Constructs the contained value in-place.
///
/// If \c *this already contains a value before the call, the contained
/// value is destroyed by calling its destructor.
///
/// \param args the arguments to pass to the constructor
template <typename...Args>
void emplace(Args&&...args);
/// \brief Constructs the contained value in-place.
///
/// If \c *this already contains a value before the call, the contained
/// value is destroyed by calling its destructor.
///
/// \param ilist the initializer list to pass to the constructor
/// \param args the arguments to pass to the constructor
template <typename U,typename...Args >
void emplace(std::initializer_list<U> ilist, Args&&...args);
};
//=========================================================================
// non-member functions : class : optional
//=========================================================================
//-------------------------------------------------------------------------
// Comparison
//-------------------------------------------------------------------------
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator==(const optional<T>& lhs, const optional<T>& rhs);
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator!=(const optional<T>& lhs, const optional<T>& rhs);
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator<(const optional<T>& lhs, const optional<T>& rhs);
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator>(const optional<T>& lhs, const optional<T>& rhs);
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator<=(const optional<T>& lhs, const optional<T>& rhs);
template <typename T>
BPSTD_CPP14_CONSTEXPR bool operator>=(const optional<T>& lhs, const optional<T>& rhs);
//-------------------------------------------------------------------------
template <typename T>
constexpr bool operator==(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator==(nullopt_t, const optional<T>& opt) noexcept;
template <typename T>
constexpr bool operator!=(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator!=(nullopt_t, const optional<T>& opt) noexcept;
template <typename T>
constexpr bool operator<(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator<(nullopt_t, const optional<T>& opt) noexcept;
template <typename T>
constexpr bool operator>(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator>(nullopt_t, const optional<T>& opt) noexcept;
template <typename T>
constexpr bool operator<=(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator<=(nullopt_t, const optional<T>& opt) noexcept;
template <typename T>
constexpr bool operator>=(const optional<T>& opt, nullopt_t) noexcept;
template <typename T>
constexpr bool operator>=(nullopt_t, const optional<T>& opt) noexcept;
//-------------------------------------------------------------------------
template <typename T>
constexpr bool operator==(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator==(const T& value, const optional<T>& opt);
template <typename T>
constexpr bool operator!=(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator!=(const T& value, const optional<T>& opt);
template <typename T>
constexpr bool operator<(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator<(const T& value, const optional<T>& opt);
template <typename T>
constexpr bool operator>(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator>(const T& value, const optional<T>& opt);
template <typename T>
constexpr bool operator<=(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator<=(const T& value, const optional<T>& opt);
template <typename T>
constexpr bool operator>=(const optional<T>& opt, const T& value);
template <typename T>
constexpr bool operator>=(const T& value, const optional<T>& opt);
//-------------------------------------------------------------------------
// Utilities
//-------------------------------------------------------------------------
/// \brief Creates an optional object from \p value
///
/// \param value the value to construct the optional from
template <typename T>
constexpr optional<decay_t<T>> make_optional(T&& value);
/// \brief Creates an optional object of type \p T from the given \p args
///
/// \tparam T the type to construct
/// \param args the arguments to pass to \p T's constructor
template <typename T, typename... Args >
constexpr optional<T> make_optional(Args&&... args);
/// \brief Creates an optional object of type \p T from the given
/// \p il \p args
///
/// \tparam T the type to construct
/// \param il the initializer list to pass
/// \param args the arguments to pass to \p T's constructor
template <typename T, typename U, typename... Args >
constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args);
//-------------------------------------------------------------------------
/// \brief Swaps \p lhs and \p rhs
///
/// \param lhs the left optional to swap
/// \param rhs the right optional to swap
template <typename T>
void swap(optional<T>& lhs, optional<T>& rhs);
} // namespace bpstd
//=============================================================================
// class : detail::optional_base<T,true>
//=============================================================================
//-----------------------------------------------------------------------------
// Constructors
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::detail::optional_base<T,true>
::optional_base(nullopt_t)
noexcept
: m_storage{},
m_engaged{false}
{
}
template <typename T>
template <typename...Args>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::detail::optional_base<T,true>::optional_base(in_place_t, Args&&...args)
noexcept(std::is_nothrow_constructible<T,Args...>::value)
: m_storage(in_place, bpstd::forward<Args>(args)...),
m_engaged{true}
{
}
//-----------------------------------------------------------------------------
// Protected Observers
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
T* bpstd::detail::optional_base<T,true>::val()
noexcept
{
return &m_storage.something;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
const T* bpstd::detail::optional_base<T,true>::val()
const noexcept
{
return &m_storage.something;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::detail::optional_base<T,true>::contains_value()
const noexcept
{
return m_engaged;
}
//-----------------------------------------------------------------------------
// Protected Modifiers
//-----------------------------------------------------------------------------
template <typename T>
template <typename...Args>
inline BPSTD_INLINE_VISIBILITY
void bpstd::detail::optional_base<T,true>::construct(Args&&...args)
{
m_storage.something = T(bpstd::forward<Args>(args)...);
m_engaged = true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
void bpstd::detail::optional_base<T,true>::destruct()
{
m_engaged = false;
}
//=============================================================================
// class : detail::optional_base<T,false>
//=============================================================================
//-----------------------------------------------------------------------------
// Constructors / Destructor
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::detail::optional_base<T,false>
::optional_base(nullopt_t)
noexcept
: m_storage{},
m_engaged{false}
{
}
template <typename T>
template <typename...Args>
inline BPSTD_INLINE_VISIBILITY
bpstd::detail::optional_base<T,false>
::optional_base(in_place_t, Args&&...args)
noexcept(std::is_nothrow_constructible<T,Args...>::value)
: m_storage(in_place, bpstd::forward<Args>(args)...),
m_engaged{true}
{
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::detail::optional_base<T,false>::~optional_base<T,false>()
noexcept(std::is_nothrow_destructible<T>::value)
{
if (m_engaged) {
m_storage.something.~T();
}
}
//-----------------------------------------------------------------------------
// Protected Observers
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
T* bpstd::detail::optional_base<T,false>::val()
noexcept
{
return &m_storage.something;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
const T* bpstd::detail::optional_base<T,false>::val()
const noexcept
{
return &m_storage.something;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bool bpstd::detail::optional_base<T,false>::contains_value()
const noexcept
{
return m_engaged;
}
//-----------------------------------------------------------------------------
// Protected Modifiers
//-----------------------------------------------------------------------------
template <typename T>
template <typename...Args>
inline BPSTD_INLINE_VISIBILITY
void bpstd::detail::optional_base<T,false>::construct(Args&&...args)
{
new (&m_storage.something) T(bpstd::forward<Args>(args)...);
m_engaged = true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
void bpstd::detail::optional_base<T,false>::destruct()
{
if (m_engaged) {
m_storage.something.~T();
m_engaged = false;
}
}
//=============================================================================
// class : optional
//=============================================================================
//-----------------------------------------------------------------------------
// Constructor / Assignment
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::optional()
noexcept
: base_type{ nullopt }
{
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::optional(nullopt_t)
noexcept
: optional{}
{
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>
::optional(detail::enable_overload_if_t<std::is_copy_constructible<T>::value,const optional&> other)
: optional{}
{
if (other.has_value())
{
base_type::construct(*other);
}
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>
::optional(detail::enable_overload_if_t<std::is_move_constructible<T>::value,optional&&> other)
: optional{}
{
if (other.has_value())
{
base_type::construct(bpstd::move(*other));
}
}
//-----------------------------------------------------------------------------
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_copy_convertible<T,U>::value && std::is_convertible<const U&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>::optional(const optional<U>& other)
: optional{}
{
if (other.has_value())
{
base_type::construct(*other);
}
}
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_copy_convertible<T,U>::value && !std::is_convertible<const U&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>::optional(const optional<U>& other)
: optional{}
{
if (other.has_value())
{
base_type::construct(*other);
}
}
//-----------------------------------------------------------------------------
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_move_convertible<T,U>::value && std::is_convertible<U&&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>::optional(optional<U>&& other)
: optional{}
{
if (other.has_value())
{
base_type::construct(bpstd::move(*other));
}
}
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_move_convertible<T,U>::value && !std::is_convertible<U&&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>::optional(optional<U>&& other)
: optional{}
{
if (other.has_value())
{
base_type::construct(bpstd::move(*other));
}
}
template <typename T>
template <typename...Args, typename>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::optional(in_place_t, Args&&...args)
: base_type{ in_place, bpstd::forward<Args>(args)... }
{
}
template <typename T>
template <typename U, typename...Args, typename>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>
::optional( in_place_t,
std::initializer_list<U> ilist,
Args&&...args )
: base_type{ in_place, ilist, bpstd::forward<Args>(args)... }
{
}
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_value_convertible<T,U>::value && std::is_convertible<U&&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::optional(U&& value)
: base_type{ in_place, bpstd::forward<U>(value) }
{
}
template <typename T>
template <typename U,
bpstd::enable_if_t<bpstd::detail::optional_is_value_convertible<T,U>::value && !std::is_convertible<U&&, T>::value>*>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::optional(U&& value)
: base_type{ in_place, bpstd::forward<U>(value) }
{
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>& bpstd::optional<T>::operator=(nullopt_t)
{
base_type::destruct();
return (*this);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>&
bpstd::optional<T>::operator=(detail::enable_overload_if_t<std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,const optional&> other)
{
if (has_value() && other.has_value()) {
(*base_type::val()) = (*other);
} else if (has_value()) {
base_type::destruct();
} else if (other.has_value()) {
base_type::construct(*other);
}
return (*this);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>&
bpstd::optional<T>::operator=(detail::enable_overload_if_t<std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,optional&&> other)
{
if (has_value() && other.has_value()) {
(*base_type::val()) = bpstd::move(*other);
} else if (has_value()) {
base_type::destruct();
} else if (other.has_value()) {
base_type::construct(bpstd::move( *other ));
}
return (*this);
}
template <typename T>
template <typename U, typename>
inline BPSTD_INLINE_VISIBILITY
bpstd::optional<T>& bpstd::optional<T>::operator=(U&& value)
{
if (has_value()) {
(*base_type::val()) = bpstd::forward<U>(value);
} else {
base_type::construct(bpstd::forward<U>(value));
}
return (*this);
}
//-----------------------------------------------------------------------------
// Observers
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T>::operator bool()
const noexcept
{
return base_type::contains_value();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::optional<T>::has_value()
const noexcept
{
return base_type::contains_value();
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type*
bpstd::optional<T>::operator->()
noexcept
{
return base_type::val();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
const typename bpstd::optional<T>::value_type*
bpstd::optional<T>::operator->()
const noexcept
{
return base_type::val();
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type&
bpstd::optional<T>::operator*()
& noexcept
{
return *base_type::val();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type&&
bpstd::optional<T>::operator*()
&& noexcept
{
return bpstd::move(*base_type::val());
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
const typename bpstd::optional<T>::value_type&
bpstd::optional<T>::operator*()
const & noexcept
{
return *base_type::val();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
const typename bpstd::optional<T>::value_type&&
bpstd::optional<T>::operator*()
const && noexcept
{
return bpstd::move(*base_type::val());
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type&
bpstd::optional<T>::value()
&
{
if (static_cast<bool>(*this)) {
return *base_type::val();
}
assert(false);
return *base_type::val();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type&&
bpstd::optional<T>::value()
&&
{
if (static_cast<bool>(*this)) {
return bpstd::move(*base_type::val());
}
assert(false);
return bpstd::move(*base_type::val());
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
const typename bpstd::optional<T>::value_type&
bpstd::optional<T>::value()
const &
{
if (static_cast<bool>(*this)) {
return *base_type::val();
}
assert(false);
return *base_type::val();
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
const typename bpstd::optional<T>::value_type&&
bpstd::optional<T>::value()
const &&
{
if (static_cast<bool>(*this)) {
return bpstd::move(*base_type::val());
}
assert(false);
return bpstd::move(*base_type::val());
}
//-----------------------------------------------------------------------------
template <typename T>
template <typename U>
inline BPSTD_INLINE_VISIBILITY constexpr
typename bpstd::optional<T>::value_type
bpstd::optional<T>::value_or(U&& default_value)
const &
{
return bool(*this) ? (*base_type::val()) : bpstd::forward<U>(default_value);
}
template <typename T>
template <typename U>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
typename bpstd::optional<T>::value_type
bpstd::optional<T>::value_or(U&& default_value)
&&
{
return bool(*this) ? (*base_type::val()) : bpstd::forward<U>(default_value);
}
//-----------------------------------------------------------------------------
// Modifiers
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY
void bpstd::optional<T>::swap(optional& other)
{
using std::swap;
if (has_value() && other.has_value()){
swap(*base_type::val(), *other);
} else if (has_value()) {
other = bpstd::move(*this);
reset(); // leave this unengaged
} else if (other.has_value()) {
*this = bpstd::move(other);
other.reset(); // leave 'other' unengaged
}
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
void bpstd::optional<T>::reset()
noexcept(std::is_nothrow_destructible<T>::value)
{
base_type::destruct();
}
//-----------------------------------------------------------------------------
template <typename T>
template <typename...Args>
inline BPSTD_INLINE_VISIBILITY
void bpstd::optional<T>::emplace(Args&&...args)
{
base_type::destruct();
base_type::construct(bpstd::forward<Args>(args)...);
}
template <typename T>
template <typename U, typename...Args>
inline BPSTD_INLINE_VISIBILITY
void bpstd::optional<T>::emplace(std::initializer_list<U> ilist,
Args&&...args)
{
base_type::destruct();
base_type::construct(ilist, bpstd::forward<Args>(args)...);
}
//=============================================================================
// Equality Operators
//=============================================================================
//-----------------------------------------------------------------------------
// Comparison
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator==(const optional<T>& lhs, const optional<T>& rhs)
{
if (static_cast<bool>(lhs) != static_cast<bool>(rhs)) {
return false;
}
if (!static_cast<bool>(lhs)) {
return true;
}
return *lhs == *rhs;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator!=(const optional<T>& lhs, const optional<T>& rhs)
{
if (static_cast<bool>(lhs) != static_cast<bool>(rhs)) {
return true;
}
if (!static_cast<bool>(lhs)) {
return false;
}
return *lhs != *rhs;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator<(const optional<T>& lhs, const optional<T>& rhs)
{
if (!static_cast<bool>(rhs)) {
return false;
}
if (!static_cast<bool>(lhs)) {
return true;
}
return *lhs < *rhs;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator>(const optional<T>& lhs, const optional<T>& rhs)
{
if (!static_cast<bool>(lhs)) {
return false;
}
if (!static_cast<bool>(rhs)) {
return true;
}
return *lhs > *rhs;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator<=(const optional<T>& lhs, const optional<T>& rhs)
{
if (!static_cast<bool>(lhs)) {
return true;
}
if (!static_cast<bool>(rhs)) {
return false;
}
return *lhs <= *rhs;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY BPSTD_CPP14_CONSTEXPR
bool
bpstd::operator>=(const optional<T>& lhs, const optional<T>& rhs)
{
if (!static_cast<bool>(rhs)) {
return true;
}
if (!static_cast<bool>(lhs)) {
return false;
}
return *lhs >= *rhs;
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator==(const optional<T>& opt, nullopt_t)
noexcept
{
return !opt;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator==(nullopt_t, const optional<T>& opt)
noexcept
{
return !opt;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator!=(const optional<T>& opt, nullopt_t)
noexcept
{
return static_cast<bool>(opt);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator!=(nullopt_t, const optional<T>& opt)
noexcept
{
return static_cast<bool>(opt);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<(const optional<T>&, nullopt_t)
noexcept
{
return false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<(nullopt_t, const optional<T>& opt)
noexcept
{
return static_cast<bool>(opt);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>(const optional<T>& opt, nullopt_t)
noexcept
{
return static_cast<bool>(opt);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>(nullopt_t, const optional<T>&)
noexcept
{
return false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<=(const optional<T>& opt, nullopt_t)
noexcept
{
return !opt;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<=(nullopt_t, const optional<T>&)
noexcept
{
return true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>=(const optional<T>&, nullopt_t)
noexcept
{
return true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>=(nullopt_t, const optional<T>& opt)
noexcept
{
return !opt;
}
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator==(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt == value : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator==(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value == *opt : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator!=(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt != value : true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator!=(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value != *opt : true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt < value : true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value < *opt : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt > value : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value > *opt : true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<=(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt <= value : true;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator<=(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value <= *opt : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>=(const optional<T>& opt, const T& value)
{
return static_cast<bool>(opt) ? *opt >= value : false;
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bool bpstd::operator>=(const T& value, const optional<T>& opt)
{
return static_cast<bool>(opt) ? value >= *opt : true;
}
//-----------------------------------------------------------------------------
// Non-member functions
//-----------------------------------------------------------------------------
template <typename T>
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<bpstd::decay_t<T>> bpstd::make_optional(T&& value)
{
return optional<decay_t<T>>(bpstd::forward<T>(value));
}
template <typename T, typename... Args >
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T> bpstd::make_optional(Args&&... args)
{
return optional<T>(in_place, bpstd::forward<Args>(args)...);
}
template <typename T, typename U, typename... Args >
inline BPSTD_INLINE_VISIBILITY constexpr
bpstd::optional<T> bpstd::make_optional(std::initializer_list<U> il, Args&&... args)
{
return optional<T>(
in_place,
std::forward<std::initializer_list<U>>(il),
std::forward<Args>(args)...
);
}
template <typename T>
inline BPSTD_INLINE_VISIBILITY
void bpstd::swap(optional<T>& lhs, optional<T>& rhs)
{
lhs.swap(rhs);
}
BPSTD_COMPILER_DIAGNOSTIC_POSTAMBLE
#endif /* BPSTD_OPTIONAL_HPP */