/* Utilities for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_UTILITY_HH #define OCTA_UTILITY_HH #include #include "octa/type_traits.hh" namespace octa { /* move */ template static inline constexpr RemoveReference &&move(T &&v) { return static_cast &&>(v); } /* forward */ template static inline constexpr T &&forward(RemoveReference &v) { return static_cast(v); } template static inline constexpr T &&forward(RemoveReference &&v) { return static_cast(v); } /* exchange */ template T exchange(T &v, U &&nv) { T old = move(v); v = forward(nv); return old; } /* declval */ template AddRvalueReference declval(); /* swap */ namespace detail { template struct SwapTest { template struct Test {}; template static char test(Test *); template static int test(...); static constexpr bool value = (sizeof(test(0)) == sizeof(char)); }; template inline void swap(T &a, T &b, EnableIf< octa::detail::SwapTest::value, bool > = true) { a.swap(b); } template inline void swap(T &a, T &b, EnableIf< !octa::detail::SwapTest::value, bool > = true) { T c(octa::move(a)); a = octa::move(b); b = octa::move(c); } } template void swap(T &a, T &b) { octa::detail::swap(a, b); } template void swap(T (&a)[N], T (&b)[N]) { for (octa::Size i = 0; i < N; ++i) { octa::swap(a[i], b[i]); } } /* 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(octa::forward(x)), second(octa::forward(y)) {} template Pair(const Pair &v): first(v.first), second(v.second) {} template Pair(Pair &&v): first(octa::move(v.first)), second(octa::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 = octa::move(v.first); second = octa::move(v.second); return *this; } template Pair &operator=(Pair &&v) { first = octa::forward(v.first); second = octa::forward(v.second); return *this; } void swap(Pair &v) { octa::swap(first, v.first); octa::swap(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 octa::detail::MakePairRetBase>::Type; }; } /* namespace detail */ template Pair::Type, typename octa::detail::MakePairRet::Type > make_pair(T &&a, U &&b) { return Pair::Type, typename octa::detail::MakePairRet::Type >(forward(a), forward(b));; } namespace detail { template, octa::RemoveCv>::value, bool = octa::IsEmpty::value, bool = octa::IsEmpty::value > struct CompressedPairSwitch; /* neither empty */ template struct CompressedPairSwitch { enum { value = 0 }; }; /* first empty */ template struct CompressedPairSwitch { enum { value = 1 }; }; /* second empty */ template struct CompressedPairSwitch { enum { value = 2 }; }; /* both empty, not the same */ template struct CompressedPairSwitch { enum { value = 3 }; }; /* both empty and same */ template struct CompressedPairSwitch { enum { value = 1 }; }; template::value> struct CompressedPairBase; template struct CompressedPairBase { T p_first; U p_second; template CompressedPairBase(TT &&a, UU &&b): p_first(octa::forward(a)), p_second(octa::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) { octa::swap(p_first, v.p_first); octa::swap(p_second, v.p_second); } }; template struct CompressedPairBase: T { U p_second; template CompressedPairBase(TT &&a, UU &&b): T(octa::forward(a)), p_second(octa::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) { octa::swap(p_second, v.p_second); } }; template struct CompressedPairBase: U { T p_first; template CompressedPairBase(TT &&a, UU &&b): U(octa::forward(b)), p_first(octa::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) { octa::swap(p_first, v.p_first); } }; template struct CompressedPairBase: T, U { template CompressedPairBase(TT &&a, UU &&b): T(octa::forward(a)), U(octa::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(octa::forward(a), octa::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 octa */ #endif