pocketpy/3rd/numpy/include/xtl/xoptional.hpp
Anurag Bhat 86b4fc623c
Merge numpy to pocketpy (#303)
* Merge numpy to pocketpy

* Add CI

* Fix CI
2024-09-02 16:22:41 +08:00

1332 lines
53 KiB
C++

/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XTL_OPTIONAL_HPP
#define XTL_OPTIONAL_HPP
#include <cmath>
#include <ostream>
#include <type_traits>
#include <utility>
#ifdef __CLING__
#include <nlohmann/json.hpp>
#endif
#include "xoptional_meta.hpp"
#include "xclosure.hpp"
#include "xfunctional.hpp"
#include "xmeta_utils.hpp"
#include "xtl_config.hpp"
#include "xtype_traits.hpp"
namespace xtl
{
template <class T, class B>
auto optional(T&& t, B&& b) noexcept;
/************************
* optional declaration *
************************/
/**
* @class xoptional
* @brief Optional value handler.
*
* The xoptional is an optional proxy. It holds a value (or a reference on a value) and a flag (or reference on a flag)
* indicating whether the element should be considered missing.
*
* xoptional is different from std::optional
*
* - no `operator->()` that returns a pointer.
* - no `operator*()` that returns a value.
*
* The only way to access the underlying value and flag is with the `value` and `value_or` methods.
*
* - no explicit convertion to bool. This may lead to confusion when the underlying value type is boolean too.
*
* @tparam CT Closure type for the value.
* @tparam CB Closure type for the missing flag. A falsy flag means that the value is missing.
*
* \ref xoptional is used both as a value type (with CT and CB being value types) and reference type for containers
* with CT and CB being reference types. In other words, it serves as a reference proxy.
*
*/
template <class CT, class CB>
class xoptional
{
public:
using self_type = xoptional<CT, CB>;
using value_closure = CT;
using flag_closure = CB;
using value_type = std::decay_t<CT>;
using flag_type = std::decay_t<CB>;
// Constructors
inline xoptional()
: m_value(), m_flag(false)
{
}
template <class T,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
std::is_constructible<CT, T&&>,
std::is_convertible<T&&, CT>
>::value,
bool
> = true>
inline constexpr xoptional(T&& rhs)
: m_value(std::forward<T>(rhs)), m_flag(true)
{
}
template <class T,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
std::is_constructible<CT, T&&>,
negation<std::is_convertible<T&&, CT>>
>::value,
bool
> = false>
inline explicit constexpr xoptional(T&& value)
: m_value(std::forward<T>(value)), m_flag(true)
{
}
template <class CTO, class CBO,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_constructible<CT, std::add_lvalue_reference_t<std::add_const_t<CTO>>>,
std::is_constructible<CB, std::add_lvalue_reference_t<std::add_const_t<CBO>>>,
conjunction<
std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CTO>>, CT>,
std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CBO>>, CB>
>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>
>::value,
bool
> = true>
inline constexpr xoptional(const xoptional<CTO, CBO>& rhs)
: m_value(rhs.value()), m_flag(rhs.has_value())
{
}
template <class CTO, class CBO,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_constructible<CT, std::add_lvalue_reference_t<std::add_const_t<CTO>>>,
std::is_constructible<CB, std::add_lvalue_reference_t<std::add_const_t<CBO>>>,
disjunction<
negation<std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CTO>>, CT>>,
negation<std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CBO>>, CB>>
>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>
>::value,
bool
> = false>
inline explicit constexpr xoptional(const xoptional<CTO, CBO>& rhs)
: m_value(rhs.value()), m_flag(rhs.has_value())
{
}
template <class CTO, class CBO,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_constructible<CT, std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>>,
std::is_constructible<CB, std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>>,
conjunction<
std::is_convertible<std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>, CT>,
std::is_convertible<std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>, CB>
>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>
>::value,
bool
> = true>
inline constexpr xoptional(xoptional<CTO, CBO>&& rhs)
: m_value(std::move(rhs).value()), m_flag(std::move(rhs).has_value())
{
}
template <class CTO, class CBO,
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_constructible<CT, std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>>,
std::is_constructible<CB, std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>>,
disjunction<
negation<std::is_convertible<std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>, CT>>,
negation<std::is_convertible<std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>, CB>>
>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>
>::value,
bool
> = false>
inline explicit constexpr xoptional(xoptional<CTO, CBO>&& rhs)
: m_value(std::move(rhs).value()), m_flag(std::move(rhs).has_value())
{
}
xoptional(value_type&&, flag_type&&);
xoptional(std::add_lvalue_reference_t<CT>, std::add_lvalue_reference_t<CB>);
xoptional(value_type&&, std::add_lvalue_reference_t<CB>);
xoptional(std::add_lvalue_reference_t<CT>, flag_type&&);
// Assignment
template <class T>
std::enable_if_t<
conjunction<
negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
std::is_assignable<std::add_lvalue_reference_t<CT>, T>
>::value,
xoptional&>
inline operator=(T&& rhs)
{
m_value = std::forward<T>(rhs);
m_flag = true;
return *this;
}
template <class CTO, class CBO>
std::enable_if_t<conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_assignable<std::add_lvalue_reference_t<CT>, CTO>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>,
negation<detail::assigns_from_xoptional<CT, CTO, CBO>>
>::value,
xoptional&>
inline operator=(const xoptional<CTO, CBO>& rhs)
{
m_value = rhs.value();
m_flag = rhs.has_value();
return *this;
}
template <class CTO, class CBO>
std::enable_if_t<conjunction<
negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
std::is_assignable<std::add_lvalue_reference_t<CT>, CTO>,
negation<detail::converts_from_xoptional<CT, CTO, CBO>>,
negation<detail::assigns_from_xoptional<CT, CTO, CBO>>
>::value,
xoptional&>
inline operator=(xoptional<CTO, CBO>&& rhs)
{
m_value = std::move(rhs).value();
m_flag = std::move(rhs).has_value();
return *this;
}
// Operators
template <class CTO, class CBO>
xoptional& operator+=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator-=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator*=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator/=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator%=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator&=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator|=(const xoptional<CTO, CBO>&);
template <class CTO, class CBO>
xoptional& operator^=(const xoptional<CTO, CBO>&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator+=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator-=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator*=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator/=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator%=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator&=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator|=(const T&);
template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
xoptional& operator^=(const T&);
// Access
std::add_lvalue_reference_t<CT> value() & noexcept;
std::add_lvalue_reference_t<std::add_const_t<CT>> value() const & noexcept;
std::conditional_t<std::is_reference<CT>::value, apply_cv_t<CT, value_type>&, value_type> value() && noexcept;
std::conditional_t<std::is_reference<CT>::value, const value_type&, value_type> value() const && noexcept;
template <class U>
value_type value_or(U&&) const & noexcept;
template <class U>
value_type value_or(U&&) const && noexcept;
// Access
std::add_lvalue_reference_t<CB> has_value() & noexcept;
std::add_lvalue_reference_t<std::add_const_t<CB>> has_value() const & noexcept;
std::conditional_t<std::is_reference<CB>::value, apply_cv_t<CB, flag_type>&, flag_type> has_value() && noexcept;
std::conditional_t<std::is_reference<CB>::value, const flag_type&, flag_type> has_value() const && noexcept;
// Swap
void swap(xoptional& other);
// Comparison
template <class CTO, class CBO>
bool equal(const xoptional<CTO, CBO>& rhs) const noexcept;
template <class CTO, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<CTO>)>
bool equal(const CTO& rhs) const noexcept;
xclosure_pointer<self_type&> operator&() &;
xclosure_pointer<const self_type&> operator&() const &;
xclosure_pointer<self_type> operator&() &&;
private:
template <class CTO, class CBO>
friend class xoptional;
CT m_value;
CB m_flag;
};
// value
template <class T, class U = disable_xoptional<std::decay_t<T>>>
T&& value(T&& v)
{
return std::forward<T>(v);
}
template <class CT, class CB>
decltype(auto) value(xtl::xoptional<CT, CB>&& v)
{
return std::move(v).value();
}
template <class CT, class CB>
decltype(auto) value(xtl::xoptional<CT, CB>& v)
{
return v.value();
}
template <class CT, class CB>
decltype(auto) value(const xtl::xoptional<CT, CB>& v)
{
return v.value();
}
// has_value
template <class T, class U = disable_xoptional<std::decay_t<T>>>
bool has_value(T&&)
{
return true;
}
template <class CT, class CB>
decltype(auto) has_value(xtl::xoptional<CT, CB>&& v)
{
return std::move(v).has_value();
}
template <class CT, class CB>
decltype(auto) has_value(xtl::xoptional<CT, CB>& v)
{
return v.has_value();
}
template <class CT, class CB>
decltype(auto) has_value(const xtl::xoptional<CT, CB>& v)
{
return v.has_value();
}
/***************************************
* optional and missing implementation *
***************************************/
/**
* @brief Returns an \ref xoptional holding closure types on the specified parameters
*
* @tparam t the optional value
* @tparam b the boolean flag
*/
template <class T, class B>
inline auto optional(T&& t, B&& b) noexcept
{
using optional_type = xoptional<closure_type_t<T>, closure_type_t<B>>;
return optional_type(std::forward<T>(t), std::forward<B>(b));
}
/**
* @brief Returns an \ref xoptional for a missig value
*/
template <class T>
xoptional<T, bool> missing() noexcept
{
return xoptional<T, bool>(T(), false);
}
/****************************
* xoptional implementation *
****************************/
// Constructors
template <class CT, class CB>
xoptional<CT, CB>::xoptional(value_type&& value, flag_type&& flag)
: m_value(std::move(value)), m_flag(std::move(flag))
{
}
template <class CT, class CB>
xoptional<CT, CB>::xoptional(std::add_lvalue_reference_t<CT> value, std::add_lvalue_reference_t<CB> flag)
: m_value(value), m_flag(flag)
{
}
template <class CT, class CB>
xoptional<CT, CB>::xoptional(value_type&& value, std::add_lvalue_reference_t<CB> flag)
: m_value(std::move(value)), m_flag(flag)
{
}
template <class CT, class CB>
xoptional<CT, CB>::xoptional(std::add_lvalue_reference_t<CT> value, flag_type&& flag)
: m_value(value), m_flag(std::move(flag))
{
}
// Operators
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator+=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value += rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator-=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value -= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator*=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value *= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator/=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value /= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator%=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value %= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator&=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value &= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator|=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value |= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::operator^=(const xoptional<CTO, CBO>& rhs) -> xoptional&
{
m_flag = m_flag && rhs.m_flag;
if (m_flag)
{
m_value ^= rhs.m_value;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator+=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value += rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator-=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value -= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator*=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value *= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator/=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value /= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator%=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value %= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator&=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value &= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator|=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value |= rhs;
}
return *this;
}
template <class CT, class CB>
template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
auto xoptional<CT, CB>::operator^=(const T& rhs) -> xoptional&
{
if (m_flag)
{
m_value ^= rhs;
}
return *this;
}
// Access
template <class CT, class CB>
auto xoptional<CT, CB>::value() & noexcept -> std::add_lvalue_reference_t<CT>
{
return m_value;
}
template <class CT, class CB>
auto xoptional<CT, CB>::value() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<CT>>
{
return m_value;
}
template <class CT, class CB>
auto xoptional<CT, CB>::value() && noexcept -> std::conditional_t<std::is_reference<CT>::value, apply_cv_t<CT, value_type>&, value_type>
{
return m_value;
}
template <class CT, class CB>
auto xoptional<CT, CB>::value() const && noexcept -> std::conditional_t<std::is_reference<CT>::value, const value_type&, value_type>
{
return m_value;
}
template <class CT, class CB>
template <class U>
auto xoptional<CT, CB>::value_or(U&& default_value) const & noexcept -> value_type
{
return m_flag ? m_value : std::forward<U>(default_value);
}
template <class CT, class CB>
template <class U>
auto xoptional<CT, CB>::value_or(U&& default_value) const && noexcept -> value_type
{
return m_flag ? m_value : std::forward<U>(default_value);
}
// Access
template <class CT, class CB>
auto xoptional<CT, CB>::has_value() & noexcept -> std::add_lvalue_reference_t<CB>
{
return m_flag;
}
template <class CT, class CB>
auto xoptional<CT, CB>::has_value() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<CB>>
{
return m_flag;
}
template <class CT, class CB>
auto xoptional<CT, CB>::has_value() && noexcept -> std::conditional_t<std::is_reference<CB>::value, apply_cv_t<CB, flag_type>&, flag_type>
{
return m_flag;
}
template <class CT, class CB>
auto xoptional<CT, CB>::has_value() const && noexcept -> std::conditional_t<std::is_reference<CB>::value, const flag_type&, flag_type>
{
return m_flag;
}
// Swap
template <class CT, class CB>
void xoptional<CT, CB>::swap(xoptional& other)
{
std::swap(m_value, other.m_value);
std::swap(m_flag, other.m_flag);
}
// Comparison
template <class CT, class CB>
template <class CTO, class CBO>
auto xoptional<CT, CB>::equal(const xoptional<CTO, CBO>& rhs) const noexcept -> bool
{
return (!m_flag && !rhs.m_flag) || (m_value == rhs.m_value && (m_flag && rhs.m_flag));
}
template <class CT, class CB>
template <class CTO, check_requires<is_not_xoptional_nor_xmasked_value<CTO>>>
bool xoptional<CT, CB>::equal(const CTO& rhs) const noexcept
{
return m_flag ? (m_value == rhs) : false;
}
template <class CT, class CB>
inline auto xoptional<CT, CB>::operator&() & -> xclosure_pointer<self_type&>
{
return xclosure_pointer<self_type&>(*this);
}
template <class CT, class CB>
inline auto xoptional<CT, CB>::operator&() const & -> xclosure_pointer<const self_type&>
{
return xclosure_pointer<const self_type&>(*this);
}
template <class CT, class CB>
inline auto xoptional<CT, CB>::operator&() && -> xclosure_pointer<self_type>
{
return xclosure_pointer<self_type>(std::move(*this));
}
// External operators
template <class T, class B, class OC, class OT>
inline std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xoptional<T, B>& v)
{
if (v.has_value())
{
out << v.value();
}
else
{
out << "N/A";
}
return out;
}
#ifdef __CLING__
template <class T, class B>
nlohmann::json mime_bundle_repr(const xoptional<T, B>& v)
{
auto bundle = nlohmann::json::object();
std::stringstream tmp;
tmp << v;
bundle["text/plain"] = tmp.str();
return bundle;
}
#endif
template <class T1, class B1, class T2, class B2>
inline auto operator==(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> bool
{
return e1.equal(e2);
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline bool operator==(const xoptional<T1, B1>& e1, const T2& e2) noexcept
{
return e1.equal(e2);
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline bool operator==(const T1& e1, const xoptional<T2, B2>& e2) noexcept
{
return e2.equal(e1);
}
template <class T, class B>
inline auto operator+(const xoptional<T, B>& e) noexcept
-> xoptional<std::decay_t<T>>
{
return e;
}
template <class T1, class B1, class T2, class B2>
inline auto operator!=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> bool
{
return !e1.equal(e2);
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline bool operator!=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
{
return !e1.equal(e2);
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline bool operator!=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
{
return !e2.equal(e1);
}
// Operations
template <class T, class B>
inline auto operator-(const xoptional<T, B>& e) noexcept
-> xoptional<std::decay_t<T>>
{
using value_type = std::decay_t<T>;
return e.has_value() ? -e.value() : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator+(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() + e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator+(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 + e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator+(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() + e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator-(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() - e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator-(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 - e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator-(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() - e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator*(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() * e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator*(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 * e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator*(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() * e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator/(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() / e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator/(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 / e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator/(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() / e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator%(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() % e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator%(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 % e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator%(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() % e2 : missing<value_type>();
}
template <class T, class B>
inline auto operator~(const xoptional<T, B>& e) noexcept
-> xoptional<std::decay_t<T>>
{
using value_type = std::decay_t<T>;
return e.has_value() ? ~e.value() : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator&(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() & e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator&(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 & e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator&(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() & e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator|(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() | e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator|(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 | e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator|(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() | e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator^(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() ^ e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator^(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 ^ e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator^(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() ^ e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator||(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() || e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator||(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 || e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator||(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() || e2 : missing<value_type>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator&&(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() && e2.has_value() ? e1.value() && e2.value() : missing<value_type>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator&&(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e2.has_value() ? e1 && e2.value() : missing<value_type>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator&&(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> common_optional_t<T1, T2>
{
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
return e1.has_value() ? e1.value() && e2 : missing<value_type>();
}
template <class T, class B>
inline auto operator!(const xoptional<T, B>& e) noexcept
-> xoptional<bool>
{
return e.has_value() ? !e.value() : missing<bool>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator<(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() && e2.has_value() ? e1.value() < e2.value() : missing<bool>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator<(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e2.has_value() ? e1 < e2.value() : missing<bool>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator<(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() ? e1.value() < e2 : missing<bool>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator<=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() && e2.has_value() ? e1.value() <= e2.value() : missing<bool>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator<=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e2.has_value() ? e1 <= e2.value() : missing<bool>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator<=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() ? e1.value() <= e2 : missing<bool>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator>(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() && e2.has_value() ? e1.value() > e2.value() : missing<bool>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator>(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e2.has_value() ? e1 > e2.value() : missing<bool>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator>(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() ? e1.value() > e2 : missing<bool>();
}
template <class T1, class B1, class T2, class B2>
inline auto operator>=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() && e2.has_value() ? e1.value() >= e2.value() : missing<bool>();
}
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
inline auto operator>=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
-> xoptional<bool>
{
return e2.has_value() ? e1 >= e2.value() : missing<bool>();
}
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
inline auto operator>=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
-> xoptional<bool>
{
return e1.has_value() ? e1.value() >= e2 : missing<bool>();
}
#define UNARY_OPTIONAL(NAME) \
template <class T, class B> \
inline auto NAME(const xoptional<T, B>& e) \
{ \
using std::NAME; \
return e.has_value() ? NAME(e.value()) : missing<std::decay_t<T>>(); \
}
#define UNARY_BOOL_OPTIONAL(NAME) \
template <class T, class B> \
inline xoptional<bool> NAME(const xoptional<T, B>& e) \
{ \
using std::NAME; \
return e.has_value() ? bool(NAME(e.value())) : missing<bool>(); \
}
#define BINARY_OPTIONAL_1(NAME) \
template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)> \
inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2) \
-> common_optional_t<T1, T2> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
return e1.has_value() ? NAME(e1.value(), e2) : missing<value_type>(); \
}
#define BINARY_OPTIONAL_2(NAME) \
template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)> \
inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2) \
-> common_optional_t<T1, T2> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
return e2.has_value() ? NAME(e1, e2.value()) : missing<value_type>(); \
}
#define BINARY_OPTIONAL_12(NAME) \
template <class T1, class B1, class T2, class B2> \
inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>; \
return e1.has_value() && e2.has_value() ? NAME(e1.value(), e2.value()) : missing<value_type>(); \
}
#define BINARY_OPTIONAL(NAME) \
BINARY_OPTIONAL_1(NAME) \
BINARY_OPTIONAL_2(NAME) \
BINARY_OPTIONAL_12(NAME)
#define TERNARY_OPTIONAL_1(NAME) \
template <class T1, class B1, class T2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>, is_not_xoptional_nor_xmasked_value<T3>)> \
inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2, const T3& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return e1.has_value() ? NAME(e1.value(), e2, e3) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_2(NAME) \
template <class T1, class T2, class B2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>, is_not_xoptional_nor_xmasked_value<T3>)> \
inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2, const T3& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return e2.has_value() ? NAME(e1, e2.value(), e3) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_3(NAME) \
template <class T1, class T2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>, is_not_xoptional_nor_xmasked_value<T2>)> \
inline auto NAME(const T1& e1, const T2& e2, const xoptional<T3, B3>& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return e3.has_value() ? NAME(e1, e2, e3.value()) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_12(NAME) \
template <class T1, class B1, class T2, class B2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T3>)> \
inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2, const T3& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return (e1.has_value() && e2.has_value()) ? NAME(e1.value(), e2.value(), e3) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_13(NAME) \
template <class T1, class B1, class T2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)> \
inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2, const xoptional<T3, B3>& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return (e1.has_value() && e3.has_value()) ? NAME(e1.value(), e2, e3.value()) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_23(NAME) \
template <class T1, class T2, class B2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)> \
inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2, const xoptional<T3, B3>& e3) \
-> common_optional_t<T1, T2, T3> \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return (e2.has_value() && e3.has_value()) ? NAME(e1, e2.value(), e3.value()) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL_123(NAME) \
template <class T1, class B1, class T2, class B2, class T3, class B3> \
inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2, const xoptional<T3, B3>& e3) \
{ \
using std::NAME; \
using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>; \
return (e1.has_value() && e2.has_value() && e3.has_value()) ? NAME(e1.value(), e2.value(), e3.value()) : missing<value_type>(); \
}
#define TERNARY_OPTIONAL(NAME) \
TERNARY_OPTIONAL_1(NAME) \
TERNARY_OPTIONAL_2(NAME) \
TERNARY_OPTIONAL_3(NAME) \
TERNARY_OPTIONAL_12(NAME) \
TERNARY_OPTIONAL_13(NAME) \
TERNARY_OPTIONAL_23(NAME) \
TERNARY_OPTIONAL_123(NAME)
UNARY_OPTIONAL(abs)
UNARY_OPTIONAL(fabs)
BINARY_OPTIONAL(fmod)
BINARY_OPTIONAL(remainder)
TERNARY_OPTIONAL(fma)
BINARY_OPTIONAL(fmax)
BINARY_OPTIONAL(fmin)
BINARY_OPTIONAL(fdim)
UNARY_OPTIONAL(exp)
UNARY_OPTIONAL(exp2)
UNARY_OPTIONAL(expm1)
UNARY_OPTIONAL(log)
UNARY_OPTIONAL(log10)
UNARY_OPTIONAL(log2)
UNARY_OPTIONAL(log1p)
BINARY_OPTIONAL(pow)
UNARY_OPTIONAL(sqrt)
UNARY_OPTIONAL(cbrt)
BINARY_OPTIONAL(hypot)
UNARY_OPTIONAL(sin)
UNARY_OPTIONAL(cos)
UNARY_OPTIONAL(tan)
UNARY_OPTIONAL(acos)
UNARY_OPTIONAL(asin)
UNARY_OPTIONAL(atan)
BINARY_OPTIONAL(atan2)
UNARY_OPTIONAL(sinh)
UNARY_OPTIONAL(cosh)
UNARY_OPTIONAL(tanh)
UNARY_OPTIONAL(acosh)
UNARY_OPTIONAL(asinh)
UNARY_OPTIONAL(atanh)
UNARY_OPTIONAL(erf)
UNARY_OPTIONAL(erfc)
UNARY_OPTIONAL(tgamma)
UNARY_OPTIONAL(lgamma)
UNARY_OPTIONAL(ceil)
UNARY_OPTIONAL(floor)
UNARY_OPTIONAL(trunc)
UNARY_OPTIONAL(round)
UNARY_OPTIONAL(nearbyint)
UNARY_OPTIONAL(rint)
UNARY_BOOL_OPTIONAL(isfinite)
UNARY_BOOL_OPTIONAL(isinf)
UNARY_BOOL_OPTIONAL(isnan)
#undef TERNARY_OPTIONAL
#undef TERNARY_OPTIONAL_123
#undef TERNARY_OPTIONAL_23
#undef TERNARY_OPTIONAL_13
#undef TERNARY_OPTIONAL_12
#undef TERNARY_OPTIONAL_3
#undef TERNARY_OPTIONAL_2
#undef TERNARY_OPTIONAL_1
#undef BINARY_OPTIONAL
#undef BINARY_OPTIONAL_12
#undef BINARY_OPTIONAL_2
#undef BINARY_OPTIONAL_1
#undef UNARY_OPTIONAL
/*************************
* select implementation *
*************************/
template <class B, class T1, class T2, XTL_REQUIRES(at_least_one_xoptional<B, T1, T2>)>
inline common_optional_t<T1, T2> select(const B& cond, const T1& v1, const T2& v2) noexcept
{
using bool_type = common_optional_t<B>;
using return_type = common_optional_t<T1, T2>;
bool_type opt_cond(cond);
return opt_cond.has_value() ?
opt_cond.value() ? return_type(v1) : return_type(v2) :
missing<typename return_type::value_type>();
}
}
#endif