/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * 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_XMASKED_VALUE_HPP #define XTL_XMASKED_VALUE_HPP #include "xmasked_value_meta.hpp" #include "xtype_traits.hpp" namespace xtl { template inline xmasked_value masked() noexcept { return xmasked_value(T(0), false); } /**************************** * xmasked_value declaration * *****************************/ template class xmasked_value { public: using self_type = xmasked_value; using value_type = T; using flag_type = B; template constexpr xmasked_value(T1&& value, B1&& flag); template constexpr xmasked_value(T1&& value); explicit constexpr xmasked_value(); inline operator value_type() { return m_value; } std::add_lvalue_reference_t value() & noexcept; std::add_lvalue_reference_t> value() const & noexcept; std::conditional_t::value, apply_cv_t>&, std::decay_t> value() && noexcept; std::conditional_t::value, const std::decay_t&, std::decay_t> value() const && noexcept; std::add_lvalue_reference_t visible() & noexcept; std::add_lvalue_reference_t> visible() const & noexcept; std::conditional_t::value, apply_cv_t>&, std::decay_t> visible() && noexcept; std::conditional_t::value, const std::decay_t&, std::decay_t> visible() const && noexcept; template bool equal(const xmasked_value& rhs) const noexcept; template )> bool equal(const T1& rhs) const noexcept; template void swap(xmasked_value& other); #define DEFINE_ASSIGN_OPERATOR(OP) \ template \ inline xmasked_value& operator OP(const T1& rhs) \ { \ if (m_visible) \ { \ m_value OP rhs; \ } \ return *this; \ } \ \ template \ inline xmasked_value& operator OP(const xmasked_value& rhs) \ { \ m_visible = m_visible && rhs.visible(); \ if (m_visible) \ { \ m_value OP rhs.value(); \ } \ return *this; \ } DEFINE_ASSIGN_OPERATOR(=); DEFINE_ASSIGN_OPERATOR(+=); DEFINE_ASSIGN_OPERATOR(-=); DEFINE_ASSIGN_OPERATOR(*=); DEFINE_ASSIGN_OPERATOR(/=); DEFINE_ASSIGN_OPERATOR(%=); DEFINE_ASSIGN_OPERATOR(&=); DEFINE_ASSIGN_OPERATOR(|=); DEFINE_ASSIGN_OPERATOR(^=); #undef DEFINE_ASSIGN_OPERATOR private: value_type m_value; flag_type m_visible; }; /******************************** * xmasked_value implementation * ********************************/ template template inline constexpr xmasked_value::xmasked_value(T1&& value, B1&& flag) : m_value(std::forward(value)), m_visible(std::forward(flag)) { } template template inline constexpr xmasked_value::xmasked_value(T1&& value) : m_value(std::forward(value)), m_visible(true) { } template inline constexpr xmasked_value::xmasked_value() : m_value(0), m_visible(true) { } template inline auto masked_value(T&& val) { return xmasked_value(std::forward(val)); } template inline auto masked_value(T&& val, B&& mask) { return xmasked_value(std::forward(val), std::forward(mask)); } template inline auto xmasked_value::value() & noexcept -> std::add_lvalue_reference_t { return m_value; } template inline auto xmasked_value::value() const & noexcept -> std::add_lvalue_reference_t> { return m_value; } template inline auto xmasked_value::value() && noexcept -> std::conditional_t::value, apply_cv_t>&, std::decay_t> { return m_value; } template inline auto xmasked_value::value() const && noexcept -> std::conditional_t::value, const std::decay_t&, std::decay_t> { return m_value; } template inline auto xmasked_value::visible() & noexcept -> std::add_lvalue_reference_t { return m_visible; } template inline auto xmasked_value::visible() const & noexcept -> std::add_lvalue_reference_t> { return m_visible; } template inline auto xmasked_value::visible() && noexcept -> std::conditional_t::value, apply_cv_t>&, std::decay_t> { return m_visible; } template inline auto xmasked_value::visible() const && noexcept -> std::conditional_t::value, const std::decay_t&, std::decay_t> { return m_visible; } template template inline bool xmasked_value::equal(const xmasked_value& rhs) const noexcept { return (!m_visible && !rhs.visible()) || (m_value == rhs.value() && (m_visible && rhs.visible())); } template template >> inline bool xmasked_value::equal(const T1& rhs) const noexcept { return m_visible && m_value == rhs; } template template inline void xmasked_value::swap(xmasked_value& other) { using std::swap; swap(m_value, other.m_value); swap(m_visible, other.m_visible); } template inline bool operator==(const xmasked_value& lhs, const xmasked_value& rhs) noexcept { return lhs.equal(rhs); } template >)> inline bool operator==(const T1& lhs, const xmasked_value& rhs) noexcept { return rhs.equal(lhs); } template >)> inline bool operator==(const xmasked_value& lhs, const T2& rhs) noexcept { return lhs.equal(rhs); } template inline bool operator!=(const xmasked_value& lhs, const xmasked_value& rhs) noexcept { return !lhs.equal(rhs); } template >)> inline bool operator!=(const T1& lhs, const xmasked_value& rhs) noexcept { return !rhs.equal(lhs); } template >)> inline bool operator!=(const xmasked_value& lhs, const T2& rhs) noexcept { return !lhs.equal(rhs); } template inline auto operator+(const xmasked_value& e) noexcept -> xmasked_value, std::decay_t> { return xmasked_value, std::decay_t>(e.value(), e.visible()); } template inline auto operator-(const xmasked_value& e) noexcept -> xmasked_value, std::decay_t> { return xmasked_value, std::decay_t>(-e.value(), e.visible()); } template inline auto operator~(const xmasked_value& e) noexcept -> xmasked_value> { using value_type = std::decay_t; return e.visible() ? masked_value(~e.value()) : masked(); } template inline auto operator!(const xmasked_value& e) noexcept -> xmasked_value { using return_type = xmasked_value; using value_type = typename return_type::value_type; return e.visible() ? return_type(!e.value()) : masked(); } template inline std::basic_ostream& operator<<(std::basic_ostream& out, xmasked_value v) { if (v.visible()) { out << v.value(); } else { out << "masked"; } return out; } template inline void swap(xmasked_value& lhs, xmasked_value& rhs) { lhs.swap(rhs); } #define DEFINE_OPERATOR(OP) \ template \ inline auto operator OP(const xmasked_value& e1, const xmasked_value& e2) noexcept \ -> xmasked_value, std::decay_t>> \ { \ using value_type = promote_type_t, std::decay_t>; \ return e1.visible() && e2.visible() ? masked_value(e1.value() OP e2.value()) : masked(); \ } \ \ template >)> \ inline auto operator OP(const xmasked_value& e1, const T2& e2) noexcept \ -> xmasked_value, std::decay_t>> \ { \ using value_type = promote_type_t, std::decay_t>; \ return e1.visible() ? masked_value(e1.value() OP e2) : masked(); \ } \ \ template >)> \ inline auto operator OP(const T1& e1, const xmasked_value& e2) noexcept \ -> xmasked_value, std::decay_t>> \ { \ using value_type = promote_type_t, std::decay_t>; \ return e2.visible() ? masked_value(e1 OP e2.value()) : masked(); \ } #define DEFINE_BOOL_OPERATOR(OP) \ template \ inline auto operator OP(const xmasked_value& e1, const xmasked_value& e2) noexcept \ -> xmasked_value \ { \ return e1.visible() && e2.visible() ? \ masked_value(e1.value() OP e2.value()) : \ masked(); \ } \ \ template >)> \ inline auto operator OP(const xmasked_value& e1, const T2& e2) noexcept \ -> xmasked_value \ { \ return e1.visible() ? masked_value(e1.value() OP e2) : masked(); \ } \ \ template >)> \ inline auto operator OP(const T1& e1, const xmasked_value& e2) noexcept \ -> xmasked_value \ { \ return e2.visible() ? masked_value(e1 OP e2.value()) : masked(); \ } #define DEFINE_UNARY_OPERATOR(OP) \ template \ inline xmasked_value> OP(const xmasked_value& e) \ { \ using std::OP; \ return e.visible() ? masked_value(OP(e.value())) : masked>(); \ } #define DEFINE_UNARY_BOOL_OPERATOR(OP) \ template \ inline auto OP(const xmasked_value& e) \ { \ using std::OP; \ return e.visible() ? masked_value(OP(e.value())) : masked(); \ } #define DEFINE_BINARY_OPERATOR(OP) \ template \ inline auto OP(const xmasked_value& e1, const xmasked_value& e2) \ { \ using std::OP; \ return e1.visible() && e2.visible() ? \ masked_value(OP(e1.value(), e2.value())) : \ masked(); \ } \ \ template \ inline auto OP(const xmasked_value& e1, const T2& e2) \ { \ using std::OP; \ return e1.visible() ? masked_value(OP(e1.value(), e2)) : masked(); \ } \ \ template \ inline auto OP(const T1& e1, const xmasked_value& e2) \ { \ using std::OP; \ return e2.visible() ? masked_value(OP(e1, e2.value())) : masked(); \ } #define DEFINE_TERNARY_OPERATOR_MMM(OP) \ template \ inline auto OP(const xmasked_value& e1, const xmasked_value& e2, const xmasked_value& e3) \ { \ using std::OP; \ return (e1.visible() && e2.visible() && e3.visible()) ? \ masked_value(OP(e1.value(), e2.value(), e3.value())) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_MMT(OP) \ template \ inline auto OP(const xmasked_value& e1, const xmasked_value& e2, const T3& e3) \ { \ using std::OP; \ return (e1.visible() && e2.visible()) ? \ masked_value(OP(e1.value(), e2.value(), e3)) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_MTM(OP) \ template \ inline auto OP(const xmasked_value& e1, const T2& e2, const xmasked_value& e3) \ { \ using std::OP; \ return (e1.visible() && e3.visible()) ? \ masked_value(OP(e1.value(), e2, e3.value())) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_TMM(OP) \ template \ inline auto OP(const T1& e1, const xmasked_value& e2, const xmasked_value& e3) \ { \ using std::OP; \ return (e2.visible() && e3.visible()) ? \ masked_value(OP(e1, e2.value(), e3.value())) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_TTM(OP) \ template \ inline auto OP(const T1& e1, const T2& e2, const xmasked_value& e3) \ { \ using std::OP; \ return e3.visible() ? \ masked_value(OP(e1, e2, e3.value())) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_TMT(OP) \ template \ inline auto OP(const T1& e1, const xmasked_value& e2, const T3& e3) \ { \ using std::OP; \ return e2.visible() ? \ masked_value(OP(e1, e2.value(), e3)) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR_MTT(OP) \ template \ inline auto OP(const xmasked_value& e1, const T2& e2, const T3& e3) \ { \ using std::OP; \ return e1.visible() ? \ masked_value(OP(e1.value(), e2, e3)) : \ masked(); \ } #define DEFINE_TERNARY_OPERATOR(OP) \ DEFINE_TERNARY_OPERATOR_MMM(OP) \ \ DEFINE_TERNARY_OPERATOR_MMT(OP) \ DEFINE_TERNARY_OPERATOR_MTM(OP) \ DEFINE_TERNARY_OPERATOR_TMM(OP) \ DEFINE_TERNARY_OPERATOR_TTM(OP) \ DEFINE_TERNARY_OPERATOR_TMT(OP) \ DEFINE_TERNARY_OPERATOR_MTT(OP) DEFINE_OPERATOR(+); DEFINE_OPERATOR(-); DEFINE_OPERATOR(*); DEFINE_OPERATOR(/); DEFINE_OPERATOR(%); DEFINE_BOOL_OPERATOR(||); DEFINE_BOOL_OPERATOR(&&); DEFINE_OPERATOR(&); DEFINE_OPERATOR(|); DEFINE_OPERATOR(^); DEFINE_BOOL_OPERATOR(<); DEFINE_BOOL_OPERATOR(<=); DEFINE_BOOL_OPERATOR(>); DEFINE_BOOL_OPERATOR(>=); DEFINE_UNARY_OPERATOR(abs) DEFINE_UNARY_OPERATOR(fabs) DEFINE_UNARY_OPERATOR(exp) DEFINE_UNARY_OPERATOR(exp2) DEFINE_UNARY_OPERATOR(expm1) DEFINE_UNARY_OPERATOR(log) DEFINE_UNARY_OPERATOR(log10) DEFINE_UNARY_OPERATOR(log2) DEFINE_UNARY_OPERATOR(log1p) DEFINE_UNARY_OPERATOR(sqrt) DEFINE_UNARY_OPERATOR(cbrt) DEFINE_UNARY_OPERATOR(sin) DEFINE_UNARY_OPERATOR(cos) DEFINE_UNARY_OPERATOR(tan) DEFINE_UNARY_OPERATOR(acos) DEFINE_UNARY_OPERATOR(asin) DEFINE_UNARY_OPERATOR(atan) DEFINE_UNARY_OPERATOR(sinh) DEFINE_UNARY_OPERATOR(cosh) DEFINE_UNARY_OPERATOR(tanh) DEFINE_UNARY_OPERATOR(acosh) DEFINE_UNARY_OPERATOR(asinh) DEFINE_UNARY_OPERATOR(atanh) DEFINE_UNARY_OPERATOR(erf) DEFINE_UNARY_OPERATOR(erfc) DEFINE_UNARY_OPERATOR(tgamma) DEFINE_UNARY_OPERATOR(lgamma) DEFINE_UNARY_OPERATOR(ceil) DEFINE_UNARY_OPERATOR(floor) DEFINE_UNARY_OPERATOR(trunc) DEFINE_UNARY_OPERATOR(round) DEFINE_UNARY_OPERATOR(nearbyint) DEFINE_UNARY_OPERATOR(rint) DEFINE_UNARY_BOOL_OPERATOR(isfinite) DEFINE_UNARY_BOOL_OPERATOR(isinf) DEFINE_UNARY_BOOL_OPERATOR(isnan) DEFINE_BINARY_OPERATOR(fmod) DEFINE_BINARY_OPERATOR(remainder) DEFINE_BINARY_OPERATOR(fmax) DEFINE_BINARY_OPERATOR(fmin) DEFINE_BINARY_OPERATOR(fdim) DEFINE_BINARY_OPERATOR(pow) DEFINE_BINARY_OPERATOR(hypot) DEFINE_BINARY_OPERATOR(atan2) DEFINE_TERNARY_OPERATOR(fma) #undef DEFINE_TERNARY_OPERATOR #undef DEFINE_TERNARY_OPERATOR_MMM #undef DEFINE_TERNARY_OPERATOR_MMT #undef DEFINE_TERNARY_OPERATOR_MTM #undef DEFINE_TERNARY_OPERATOR_TMM #undef DEFINE_TERNARY_OPERATOR_TTM #undef DEFINE_TERNARY_OPERATOR_TMT #undef DEFINE_TERNARY_OPERATOR_MTT #undef DEFINE_BINARY_OPERATOR #undef DEFINE_UNARY_OPERATOR #undef DEFINE_UNARY_BOOL_OPERATOR #undef DEFINE_OPERATOR #undef DEFINE_BOOL_OPERATOR } #endif