/* 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 */ struct PiecewiseConstruct {}; constexpr PiecewiseConstruct piecewise_construct = {}; template struct Pair { T first; U second; Pair() = default; ~Pair() = default; Pair(Pair const &) = default; Pair(Pair &&) = default; Pair(T const &x, U const &y): first(x), second(y) {} template Pair(TT &&x, UU &&y): first(std::forward(x)), second(std::forward(y)) {} template Pair(Pair const &v): first(v.first), second(v.second) {} template Pair(Pair &&v): first(std::move(v.first)), second(std::move(v.second)) {} template Pair(PiecewiseConstruct pc, Tuple fa, Tuple sa): Pair( pc, fa, sa, detail::MakeTupleIndices(), detail::MakeTupleIndices() ) {} Pair &operator=(Pair const &v) { first = v.first; second = v.second; return *this; } template Pair &operator=(Pair const &v) { first = v.first; second = v.second; return *this; } Pair &operator=(Pair &&v) noexcept( IsNothrowMoveAssignable && IsNothrowMoveAssignable ) { first = std::move(v.first); second = std::move(v.second); return *this; } template Pair &operator=(Pair &&v) { first = std::forward(v.first); second = std::forward(v.second); return *this; } void swap(Pair &v) noexcept( noexcept(detail::swap_adl(first, v.first)) && noexcept(detail::swap_adl(second, v.second)) ) { detail::swap_adl(first, v.first); detail::swap_adl(second, v.second); } private: template Pair( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ); }; template struct ReferenceWrapper; namespace detail { template struct MakePairRetBase { using Type = T; }; template struct MakePairRetBase> { using Type = T &; }; template struct MakePairRet { using Type = typename detail::MakePairRetBase>::Type; }; } /* namespace detail */ template inline Pair< typename detail::MakePairRet::Type, typename detail::MakePairRet::Type > make_pair(T &&a, U &&b) { return Pair< typename detail::MakePairRet::Type, typename detail::MakePairRet::Type >(std::forward(a), std::forward(b)); } template inline constexpr bool operator==(Pair const &x, Pair const &y) { return (x.first == y.first) && (x.second == y.second); } template inline constexpr bool operator!=(Pair const &x, Pair const &y) { return (x.first != y.first) || (x.second != y.second); } template inline constexpr bool operator<(Pair const &x, Pair const &y) { return (x.first < y.first) ? true : ((y.first < x.first) ? false : ((x.second < y.second) ? true : false)); } template inline constexpr bool operator>(Pair const &x, Pair const &y) { return (y < x); } template inline constexpr bool operator<=(Pair const &x, Pair const &y) { return !(y < x); } template inline constexpr bool operator>=(Pair const &x, Pair const &y) { return !(x < y); } template constexpr Size TupleSize> = 2; template struct TupleElementBase<0, Pair> { using Type = T; }; template struct TupleElementBase<1, Pair> { using Type = U; }; namespace detail { template struct GetPair; template<> struct GetPair<0> { template static T &get(Pair &p) { return p.first; } template static T const &get(Pair const &p) { return p.first; } template static T &&get(Pair &&p) { return std::forward(p.first); } template static T const &&get(Pair const &&p) { return std::forward(p.first); } }; template<> struct GetPair<1> { template static U &get(Pair &p) { return p.second; } template static U const &get(Pair const &p) { return p.second; } template static U &&get(Pair &&p) { return std::forward(p.second); } template static T const &&get(Pair const &&p) { return std::forward(p.second); } }; } template inline TupleElement> &get(Pair &p) noexcept { return detail::GetPair::get(p); } template inline TupleElement> const &get(Pair const &p) noexcept { return detail::GetPair::get(p); } template inline TupleElement> &&get(Pair &&p) noexcept { return detail::GetPair::get(std::move(p)); } template inline TupleElement> const &&get(Pair const &&p) noexcept { return detail::GetPair::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( PiecewiseConstruct, 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( PiecewiseConstruct, 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( PiecewiseConstruct, 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( PiecewiseConstruct, 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(PiecewiseConstruct 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