/* Utilities for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_UTILITY_HH #define OSTD_UTILITY_HH #include #include #include "ostd/type_traits.hh" #include "ostd/internal/tuple.hh" namespace ostd { /* declval */ template AddRvalueReference declval() noexcept; /* swap */ namespace detail { template auto test_swap(int) -> BoolConstant().swap(declval()))>>; template False test_swap(...); template inline void swap_fb( T &a, T &b, EnableIf(0))::value, bool> = true ) noexcept(noexcept(a.swap(b))) { a.swap(b); } template inline void swap_fb( T &a, T &b, EnableIf(0))::value, bool> = true ) noexcept(IsNothrowMoveConstructible && IsNothrowMoveAssignable) { T c(std::move(a)); a = std::move(b); b = std::move(c); } } template inline void swap(T &a, T &b) noexcept(noexcept(detail::swap_fb(a, b))) { detail::swap_fb(a, b); } template inline void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))) { for (Size i = 0; i < N; ++i) { swap(a[i], b[i]); } } namespace detail { namespace adl_swap { using ostd::swap; template inline void swap_adl(T &a, T &b) noexcept(noexcept(swap(a, b))) { swap(a, b); } } template inline void swap_adl(T &a, T &b) noexcept(noexcept(adl_swap::swap_adl(a, b))) { adl_swap::swap_adl(a, b); } } /* pair */ template constexpr Size TupleSize> = 2; template struct TupleElementBase<0, std::pair> { using Type = T; }; template struct TupleElementBase<1, std::pair> { using Type = U; }; template inline TupleElement> &get(std::pair &p) noexcept { return std::get(p); } template inline TupleElement> const &get(std::pair const &p) noexcept { return std::get(p); } template inline TupleElement> &&get(std::pair &&p) noexcept { return std::get(std::move(p)); } template inline TupleElement> const &&get(std::pair const &&p) noexcept { return std::get(std::move(p)); } namespace detail { template, RemoveCv>, bool = IsEmpty, bool = IsEmpty > constexpr Size CompressedPairSwitch = detail::Undefined(); /* neither empty */ template constexpr Size CompressedPairSwitch = 0; /* first empty */ template constexpr Size CompressedPairSwitch = 1; /* second empty */ template constexpr Size CompressedPairSwitch = 2; /* both empty, not the same */ template constexpr Size CompressedPairSwitch = 3; /* both empty and same */ template constexpr Size CompressedPairSwitch = 1; template> struct CompressedPairBase; template struct CompressedPairBase { T p_first; U p_second; template CompressedPairBase(TT &&a, UU &&b): p_first(std::forward(a)), p_second(std::forward(b)) {} template CompressedPairBase( std::piecewise_construct_t, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ); T &first() { return p_first; } T const &first() const { return p_first; } U &second() { return p_second; } U const &second() const { return p_second; } void swap(CompressedPairBase &v) { swap_adl(p_first, v.p_first); swap_adl(p_second, v.p_second); } }; template struct CompressedPairBase: T { U p_second; template CompressedPairBase(TT &&a, UU &&b): T(std::forward(a)), p_second(std::forward(b)) {} template CompressedPairBase( std::piecewise_construct_t, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ); T &first() { return *this; } T const &first() const { return *this; } U &second() { return p_second; } U const &second() const { return p_second; } void swap(CompressedPairBase &v) { swap_adl(p_second, v.p_second); } }; template struct CompressedPairBase: U { T p_first; template CompressedPairBase(TT &&a, UU &&b): U(std::forward(b)), p_first(std::forward(a)) {} template CompressedPairBase( std::piecewise_construct_t, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ); T &first() { return p_first; } T const &first() const { return p_first; } U &second() { return *this; } U const &second() const { return *this; } void swap(CompressedPairBase &v) { swap_adl(p_first, v.p_first); } }; template struct CompressedPairBase: T, U { template CompressedPairBase(TT &&a, UU &&b): T(std::forward(a)), U(std::forward(b)) {} template CompressedPairBase( std::piecewise_construct_t, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ); T &first() { return *this; } T const &first() const { return *this; } U &second() { return *this; } U const &second() const { return *this; } void swap(CompressedPairBase &) {} }; template struct CompressedPair: CompressedPairBase { using Base = CompressedPairBase; template CompressedPair(TT &&a, UU &&b): Base(std::forward(a), std::forward(b)) {} template CompressedPair(std::piecewise_construct_t pc, Tuple fa, Tuple sa): Base( pc, fa, sa, detail::MakeTupleIndices(), detail::MakeTupleIndices() ) {} T &first() { return Base::first(); } T const &first() const { return Base::first(); } U &second() { return Base::second(); } U const &second() const { return Base::second(); } void swap(CompressedPair &v) { Base::swap(v); } }; } /* namespace detail */ } /* namespace ostd */ #endif