/* 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 "ostd/type_traits.hh" #include "ostd/internal/tuple.hh" namespace ostd { /* move */ template inline constexpr RemoveReference &&move(T &&v) { return static_cast &&>(v); } /* forward */ template inline constexpr T &&forward(RemoveReference &v) { return static_cast(v); } template inline constexpr T &&forward(RemoveReference &&v) { return static_cast(v); } /* exchange */ template inline T exchange(T &v, U &&nv) { T old = move(v); v = forward(nv); return old; } /* declval */ template AddRvalueReference declval(); /* 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< decltype(test_swap(0))::value, bool > = true) { a.swap(b); } template inline void swap_fb(T &a, T &b, EnableIf< !decltype(test_swap(0))::value, bool > = true) { T c(move(a)); a = move(b); b = move(c); } } template inline void swap(T &a, T &b) { detail::swap_fb(a, b); } template inline void swap(T (&a)[N], T (&b)[N]) { for (Size i = 0; i < N; ++i) { swap(a[i], b[i]); } } namespace detail { template inline void swap_adl(T &a, T &b) { using ostd::swap; swap(a, b); } } /* pair */ template struct Pair { T first; U second; Pair() = default; ~Pair() = default; Pair(const Pair &) = default; Pair(Pair &&) = default; Pair(const T &x, const U &y): first(x), second(y) {} template Pair(TT &&x, UU &&y): first(forward(x)), second(forward(y)) {} template Pair(const Pair &v): first(v.first), second(v.second) {} template Pair(Pair &&v): first(move(v.first)), second(move(v.second)) {} Pair &operator=(const Pair &v) { first = v.first; second = v.second; return *this; } template Pair &operator=(const Pair &v) { first = v.first; second = v.second; return *this; } Pair &operator=(Pair &&v) { first = move(v.first); second = move(v.second); return *this; } template Pair &operator=(Pair &&v) { first = forward(v.first); second = forward(v.second); return *this; } void swap(Pair &v) { detail::swap_adl(first, v.first); detail::swap_adl(second, v.second); } }; 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::Type, typename detail::MakePairRet::Type > make_pair(T &&a, U &&b) { return Pair::Type, typename detail::MakePairRet::Type >(forward(a), forward(b));; } template inline constexpr bool operator==(const Pair &x, const Pair &y) { return (x.first == y.first) && (x.second == y.second); } template inline constexpr bool operator!=(const Pair &x, const Pair &y) { return (x.first != y.first) || (x.second != y.second); } template inline constexpr bool operator<(const Pair &x, const Pair &y) { return (x.first < y.first) ? true : ((y.first < x.first) ? false : ((x.second < y.second) ? true : false)); } template inline constexpr bool operator>(const Pair &x, const Pair &y) { return (y < x); } template inline constexpr bool operator<=(const Pair &x, const Pair &y) { return !(y < x); } template inline constexpr bool operator>=(const Pair &x, const Pair &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 const T &get(const Pair &p) { return p.first; } template static T &&get(Pair &&p) { return forward(p.first); } template static const T &&get(const Pair &&p) { return forward(p.first); } }; template<> struct GetPair<1> { template static U &get(Pair &p) { return p.second; } template static const U &get(const Pair &p) { return p.second; } template static U &&get(Pair &&p) { return forward(p.second); } template static const T &&get(const Pair &&p) { return forward(p.second); } }; } template TupleElement> &get(Pair &p) { return detail::GetPair::get(p); } template const TupleElement> &get(const Pair &p) { return detail::GetPair::get(p); } template TupleElement> &&get(Pair &&p) { return detail::GetPair::get(move(p)); } template const TupleElement> &&get(const Pair &&p) { return detail::GetPair::get(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(forward(a)), p_second(forward(b)) {} T &first() { return p_first; } const T &first() const { return p_first; } U &second() { return p_second; } const U &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(forward(a)), p_second(forward(b)) {} T &first() { return *this; } const T &first() const { return *this; } U &second() { return p_second; } const U &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(forward(b)), p_first(forward(a)) {} T &first() { return p_first; } const T &first() const { return p_first; } U &second() { return *this; } const U &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(forward(a)), U(forward(b)) {} T &first() { return *this; } const T &first() const { return *this; } U &second() { return *this; } const U &second() const { return *this; } void swap(CompressedPairBase &) {} }; template struct CompressedPair: CompressedPairBase { using Base = CompressedPairBase; template CompressedPair(TT &&a, UU &&b): Base(forward(a), forward(b)) {} T &first() { return Base::first(); } const T &first() const { return Base::first(); } U &second() { return Base::second(); } const U &second() const { return Base::second(); } void swap(CompressedPair &v) { Base::swap(v); } }; } /* namespace detail */ } /* namespace ostd */ #endif