initial implementation of tuples

master
Daniel Kolesa 2015-07-11 02:38:11 +01:00
parent 3fd83c4bbd
commit b496d130ab
3 changed files with 790 additions and 0 deletions

View File

@ -0,0 +1,282 @@
/* Some tuple internals for inclusion from various headers. Partially
* taken from the libc++ project.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_INTERNAL_TUPLE_HH
#define OCTA_INTERNAL_TUPLE_HH
#include "octa/types.hh"
#include "octa/type_traits.hh"
namespace octa {
template<typename ...A> class Tuple;
template<typename T, typename U> struct Pair;
template<typename T, Size I> struct Array;
/* tuple size */
template<typename T> struct TupleSize;
template<typename T> struct TupleSize<const T>: public TupleSize<T> {};
template<typename T> struct TupleSize<volatile T>: public TupleSize<T> {};
template<typename T> struct TupleSize<const volatile T>: public TupleSize<T> {};
/* tuple element */
namespace detail {
template<Size I, typename T> struct TupleElementBase;
template<Size I, typename T>
struct TupleElementBase<I, const T> {
using Type = AddConst<typename TupleElementBase<I, T>::Type>;
};
template<Size I, typename T>
struct TupleElementBase<I, volatile T> {
using Type = AddVolatile<typename TupleElementBase<I, T>::Type>;
};
template<Size I, typename T>
struct TupleElementBase<I, const volatile T> {
using Type = AddCv<typename TupleElementBase<I, T>::Type>;
};
}
template<Size I, typename T>
using TupleElement = typename detail::TupleElementBase<I, T>::Type;
/* is tuple-like */
template<typename T> struct IsTupleLike: False {};
template<typename T> struct IsTupleLike<const T>: IsTupleLike<T> {};
template<typename T> struct IsTupleLike<volatile T>: IsTupleLike<T> {};
template<typename T> struct IsTupleLike<const volatile T>: IsTupleLike<T> {};
/* tuple specializations */
template<typename ...A> struct IsTupleLike<Tuple<A...>>: True {};
template<Size I, typename ...A>
TupleElement<I, Tuple<A...>> &get(Tuple<A...> &);
template<Size I, typename ...A>
const TupleElement<I, Tuple<A...>> &get(const Tuple<A...> &);
template<Size I, typename ...A>
TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&);
/* pair specializations */
template<typename T, typename U> struct IsTupleLike<Pair<T, U>>: True {};
template<Size I, typename T, typename U>
TupleElement<I, Pair<T, U>> &get(Pair<T, U> &);
template<Size I, typename T, typename U>
const TupleElement<I, Pair<T, U>> &get(const Pair<T, U> &);
template<Size I, typename T, typename U>
TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&);
/* array specializations */
template<typename T, Size I> struct IsTupleLike<Array<T, I>>: True {};
template<Size I, typename T, Size S>
T &get(Array<T, S> &);
template<Size I, typename T, Size S>
const T &get(const Array<T, S> &);
template<Size I, typename T, Size S>
T &&get(Array<T, S> &&);
/* make tuple indices */
namespace detail {
template<Size ...> struct TupleIndices {};
template<Size S, typename T, Size E> struct MakeTupleIndicesBase;
template<Size S, Size ...I, Size E>
struct MakeTupleIndicesBase<S, TupleIndices<I...>, E> {
using Type = typename MakeTupleIndicesBase<S + 1,
TupleIndices<I..., S>, E>::Type;
};
template<Size E, Size ...I>
struct MakeTupleIndicesBase<E, TupleIndices<I...>, E> {
using Type = TupleIndices<I...>;
};
template<Size E, Size S>
struct MakeTupleIndicesImpl {
static_assert(S <= E, "MakeTupleIndices input error");
using Type = typename MakeTupleIndicesBase<S, TupleIndices<>, E>::Type;
};
template<Size E, Size S = 0>
using MakeTupleIndices = typename MakeTupleIndicesImpl<E, S>::Type;
}
/* tuple types */
namespace detail {
template<typename ...T> struct TupleTypes {};
template<Size I> struct TupleElementBase<I, TupleTypes<>> {
public:
static_assert(I == 0, "TupleElement index out of range");
static_assert(I != 0, "TupleElement index out of range");
};
template<typename H, typename ...T>
struct TupleElementBase<0, TupleTypes<H, T...>> {
public:
using Type = H;
};
template<Size I, typename H, typename ...T>
struct TupleElementBase<I, TupleTypes<H, T...>> {
public:
using Type = typename TupleElementBase<I - 1, TupleTypes<T...>>::Type;
};
}
template<typename ...T> struct TupleSize<detail::TupleTypes<T...>>:
IntegralConstant<Size, sizeof...(T)> {};
template<typename ...T> struct IsTupleLike<detail::TupleTypes<T...>>: True {};
/* make tuple types */
namespace detail {
template<typename TT, typename T, Size S, Size E>
struct MakeTupleTypesBase;
template<typename ...TS, typename T, Size S, Size E>
struct MakeTupleTypesBase<TupleTypes<TS...>, T, S, E> {
using TR = RemoveReference<T>;
using Type = typename MakeTupleTypesBase<TupleTypes<TS...,
Conditional<IsLvalueReference<T>::value,
TupleElement<S, TR> &,
TupleElement<S, TR>>>, T, S + 1, E>::Type;
};
template<typename ...TS, typename T, Size E>
struct MakeTupleTypesBase<TupleTypes<TS...>, T, E, E> {
using Type = TupleTypes<TS...>;
};
template<typename T, Size E, Size S>
struct MakeTupleTypesImpl {
static_assert(S <= E, "MakeTupleTypes input error");
using Type = typename MakeTupleTypesBase<TupleTypes<>, T, S, E>::Type;
};
template<typename T, Size E = TupleSize<RemoveReference<T>>::value, Size S = 0>
using MakeTupleTypes = typename MakeTupleTypesImpl<T, E, S>::Type;
}
/* tuple convertible */
namespace detail {
template<typename, typename>
struct TupleConvertibleBase: False {};
template<typename T, typename ...TT, typename U, typename ...UU>
struct TupleConvertibleBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>:
IntegralConstant<bool, IsConvertible<T, U>::value &&
TupleConvertibleBase<TupleTypes<TT...>,
TupleTypes<UU...>>::value> {};
template<>
struct TupleConvertibleBase<TupleTypes<>, TupleTypes<>>: True {};
template<bool, typename, typename>
struct TupleConvertibleApply: False {};
template<typename T, typename U>
struct TupleConvertibleApply<true, T, U>: TupleConvertibleBase<
MakeTupleTypes<T>, MakeTupleTypes<U>
> {};
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>::value,
bool = IsTupleLike<U>::value>
struct TupleConvertible: False {};
template<typename T, typename U>
struct TupleConvertible<T, U, true, true>: TupleConvertibleApply<
TupleSize<RemoveReference<T>>::value == TupleSize<U>::value, T, U
> {};
}
/* tuple constructible */
namespace detail {
template<typename, typename>
struct TupleConstructibleBase: False {};
template<typename T, typename ...TT, typename U, typename ...UU>
struct TupleConstructibleBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>:
IntegralConstant<bool, IsConstructible<U, T>::value &&
TupleConstructibleBase<TupleTypes<TT...>,
TupleTypes<UU...>>::value> {};
template<>
struct TupleConstructibleBase<TupleTypes<>, TupleTypes<>>: True {};
template<bool, typename, typename>
struct TupleConstructibleApply: False {};
template<typename T, typename U>
struct TupleConstructibleApply<true, T, U>: TupleConstructibleBase<
MakeTupleTypes<T>, MakeTupleTypes<U>
> {};
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>::value,
bool = IsTupleLike<U>::value>
struct TupleConstructible: False {};
template<typename T, typename U>
struct TupleConstructible<T, U, true, true>: TupleConstructibleApply<
TupleSize<RemoveReference<T>>::value == TupleSize<U>::value, T, U
> {};
}
/* tuple assignable */
namespace detail {
template<typename, typename>
struct TupleAssignableBase: False {};
template<typename T, typename ...TT, typename U, typename ...UU>
struct TupleAssignableBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>:
IntegralConstant<bool, IsAssignable<U &, T>::value &&
TupleAssignableBase<TupleTypes<TT...>,
TupleTypes<UU...>>::value> {};
template<>
struct TupleAssignableBase<TupleTypes<>, TupleTypes<>>: True {};
template<bool, typename, typename>
struct TupleAssignableApply: False {};
template<typename T, typename U>
struct TupleAssignableApply<true, T, U>: TupleAssignableBase<
MakeTupleTypes<T>, MakeTupleTypes<U>
> {};
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>::value,
bool = IsTupleLike<U>::value>
struct TupleAssignable: False {};
template<typename T, typename U>
struct TupleAssignable<T, U, true, true>: TupleAssignableApply<
TupleSize<RemoveReference<T>>::value == TupleSize<U>::value, T, U
> {};
}
} /* namespace octa */
#endif

444
octa/tuple.hh 100644
View File

@ -0,0 +1,444 @@
/* Tuples or OctaSTD. Partially taken from the libc++ project.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_TUPLE_HH
#define OCTA_TUPLE_HH
#include "octa/internal/tuple.hh"
#include "octa/types.hh"
#include "octa/type_traits.hh"
#include "octa/memory.hh"
#include "octa/utility.hh"
namespace octa {
/* tuple size */
template<typename ...T> struct TupleSize<Tuple<T...>>:
IntegralConstant<Size, sizeof...(T)> {};
/* tuple element */
namespace detail {
template<Size I, typename ...T>
struct TupleElementBase<I, Tuple<T...>> {
using Type = typename TupleElementBase<I, TupleTypes<T...>>::Type;
};
}
/* tuple leaf */
namespace detail {
template<Size I, typename H, bool = IsEmpty<H>::value>
struct TupleLeaf {
constexpr TupleLeaf(): p_value() {
static_assert(!IsReference<H>::value,
"attempt to default construct a reference element in a tuple");
}
template<typename A>
TupleLeaf(IntegralConstant<int, 0>, const A &): p_value() {
static_assert(!IsReference<H>::value,
"attempt to default construct a reference element in a tuple");
}
template<typename A>
TupleLeaf(IntegralConstant<int, 1>, const A &a): p_value(allocator_arg, a) {
static_assert(!IsReference<H>::value,
"attempt to default construct a reference element in a tuple");
}
template<typename A>
TupleLeaf(IntegralConstant<int, 2>, const A &a): p_value(a) {
static_assert(!IsReference<H>::value,
"attempt to default construct a reference element in a tuple");
}
template<typename T,
typename = EnableIf<And<Not<IsSame<Decay<T>, TupleLeaf>>,
IsConstructible<H, T>>::value>>
explicit TupleLeaf(T &&t): p_value(forward<T>(t)) {
static_assert(!IsReference<H>::value ||
(IsLvalueReference<H>::value &&
(IsLvalueReference<T>::value ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>::value)) ||
(IsRvalueReference<H>::value &&
!IsLvalueReference<T>::value),
"attempt to construct a reference element in a tuple with an rvalue");
}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 0>, const A &, T &&t):
p_value(forward<T>(t)) {
static_assert(!IsLvalueReference<H>::value ||
(IsLvalueReference<H>::value &&
(IsLvalueReference<T>::value ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>::value)),
"attempt to construct a reference element in a tuple with an rvalue");
}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 1>, const A &a, T &&t):
p_value(allocator_arg, a, forward<T>(t)) {
static_assert(!IsLvalueReference<H>::value ||
(IsLvalueReference<H>::value &&
(IsLvalueReference<T>::value ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>::value)),
"attempt to construct a reference element in a tuple with an rvalue");
}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 2>, const A &a, T &&t):
p_value(forward<T>(t), a) {
static_assert(!IsLvalueReference<H>::value ||
(IsLvalueReference<H>::value &&
(IsLvalueReference<T>::value ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>::value)),
"attempt to construct a reference element in a tuple with an rvalue");
}
TupleLeaf(const TupleLeaf &) = default;
TupleLeaf(TupleLeaf &&) = default;
template<typename T>
TupleLeaf &operator=(T &&t) {
p_value = forward<T>(t);
return *this;
}
void swap(TupleLeaf &t) {
octa::swap(get(), t.get());
}
H &get() { return p_value; }
const H &get() const { return p_value; }
private:
TupleLeaf &operator=(const TupleLeaf &);
H p_value;
};
template<Size I, typename H>
struct TupleLeaf<I, H, true>: private H {
constexpr TupleLeaf() {}
template<typename A>
TupleLeaf(IntegralConstant<int, 0>, const A &) {}
template<typename A>
TupleLeaf(IntegralConstant<int, 1>, const A &a):
H(allocator_arg, a) {}
template<typename A>
TupleLeaf(IntegralConstant<int, 2>, const A &a): H(a) {}
template<typename T,
typename = EnableIf<And<
Not<IsSame<Decay<T>, TupleLeaf>>,
IsConstructible<H, T>
>::value>
> explicit TupleLeaf(T &&t): H(forward<T>(t)) {}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 0>, const A &, T &&t):
H(forward<T>(t)) {}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 1>, const A &a, T &&t):
H(allocator_arg, a, forward<T>(t)) {}
template<typename T, typename A>
explicit TupleLeaf(IntegralConstant<int, 2>, const A &a, T &&t):
H(forward<T>(t), a) {}
TupleLeaf(const TupleLeaf &) = default;
TupleLeaf(TupleLeaf &&) = default;
template<typename T>
TupleLeaf &operator=(T &&t) {
H::operator=(forward<T>(t));
return *this;
}
void swap(TupleLeaf &t) {
octa::swap(get(), t.get());
}
H &get() { return (H &)*this; }
const H &get() const { return (const H &)*this; }
private:
TupleLeaf &operator=(const TupleLeaf &);
};
} /* namespace detail */
/* internal utils */
namespace detail {
template<typename ...A>
inline void tuple_swallow(A &&...) {}
template<bool ...A>
struct TupleAll: IsSame<TupleAll<A...>, TupleAll<(A, true)...>> {};
template<typename T>
struct TupleAllDefaultConstructible;
template<typename ...A>
struct TupleAllDefaultConstructible<TupleTypes<A...>>:
TupleAll<IsDefaultConstructible<A>::value...> {};
}
/* tuple implementation */
namespace detail {
template<typename, typename ...> struct TupleBase;
template<Size ...I, typename ...A>
struct TupleBase<TupleIndices<I...>, A...>: TupleLeaf<I, A>... {
constexpr TupleBase() {}
template<Size ...Ia, typename ...Aa,
Size ...Ib, typename ...Ab, typename ...T>
explicit TupleBase(TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>,
T &&...t):
TupleLeaf<Ia, Aa>(forward<T>(t))...,
TupleLeaf<Ib, Ab>()... {}
template<typename Alloc, Size ...Ia, typename ...Aa,
Size ...Ib, typename ...Ab, typename ...T>
explicit TupleBase(AllocatorArg, const Alloc &a,
TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>,
T &&...t):
TupleLeaf<Ia, Aa>(UsesAllocatorConstructor<Aa, Alloc, T>(), a,
forward<T>(t))...,
TupleLeaf<Ib, Ab>(UsesAllocatorConstructor<Ab, Alloc>(), a)...
{}
template<typename T, typename = EnableIf<
TupleConstructible<T, Tuple<A...>>::value
>> TupleBase(T &&t): TupleLeaf<I, A>(forward<
TupleElement<I, MakeTupleTypes<T>>
>(get<I>(t)))... {}
template<typename Alloc, typename T, typename = EnableIf<
TupleConvertible<T, Tuple<A...>>::value
>> TupleBase(AllocatorArg, const Alloc &a, T &&t):
TupleLeaf<I, A>(UsesAllocatorConstructor<
A, Alloc, TupleElement<I, MakeTupleTypes<T>>
>(), a, forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t)))...
{}
template<typename T>
EnableIf<TupleAssignable<T, Tuple<A...>>::value, TupleBase &>
operator=(T &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(forward<
TupleElement<I, MakeTupleTypes<T>>
>(get<I>(t)))...);
return *this;
}
TupleBase(const TupleBase &) = default;
TupleBase(TupleBase &&) = default;
TupleBase &operator=(const TupleBase &t) {
tuple_swallow(TupleLeaf<I, A>::operator=(((const TupleLeaf<I,
A> &)t).get())...);
return *this;
}
TupleBase &operator=(TupleBase &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(forward<A>
(((const TupleLeaf<I, A> &)t).get()))...);
return *this;
}
void swap(TupleBase &t) {
tuple_swallow(TupleLeaf<I, A>::swap((TupleLeaf<I, A> &)t)...);
}
};
} /* namespace detail */
template<typename ...A>
class Tuple {
using Base = detail::TupleBase<detail::MakeTupleIndices<sizeof...(A)>, A...>;
Base p_base;
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &);
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> &get(const Tuple<T...> &);
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &&);
public:
template<bool D = true, typename = EnableIf<
detail::TupleAll<(D && IsDefaultConstructible<A>::value)...>::value
>> Tuple() {}
explicit Tuple(const A &...t):
p_base(detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(),
detail::MakeTupleTypes<Tuple, 0>(), t...) {}
template<typename Alloc>
Tuple(AllocatorArg, const Alloc &a, const A &...t):
p_base(allocator_arg, a,
detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(),
detail::MakeTupleTypes<Tuple, 0>(), t...) {}
template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value, bool
> = true>
Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConstructible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value &&
!detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value, bool
> = true>
Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
template<typename Alloc, typename ...T, typename = EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
>
>::value
>> Tuple(AllocatorArg, const Alloc &a, T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
template<typename T, EnableIf<
detail::TupleConvertible<T, Tuple>::value, bool
> = true> Tuple(T &&t): p_base(forward<T>(t)) {}
template<typename T, EnableIf<
detail::TupleConstructible<T, Tuple>::value &&
!detail::TupleConvertible<T, Tuple>::value, bool
> = true> Tuple(T &&t): p_base(forward<T>(t)) {}
template<typename Alloc, typename T, typename = EnableIf<
detail::TupleConvertible<T, Tuple>::value
>> Tuple(AllocatorArg, const Alloc &a, T &&t):
p_base(allocator_arg, a, forward<T>(t)) {}
template<typename T, typename = EnableIf<
detail::TupleAssignable<T, Tuple>::value
>> Tuple &operator=(T &&t) {
p_base.operator=(forward<T>(t));
return *this;
}
void swap(Tuple &t) {
p_base.swap(t.p_base);
}
};
template<> class Tuple<> {
public:
constexpr Tuple() {}
template<typename A> Tuple(AllocatorArg, const A &) {}
template<typename A> Tuple(AllocatorArg, const A &, const Tuple &) {}
void swap(Tuple &) {}
};
/* get */
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &t) {
using Type = TupleElement<I, Tuple<A...>>;
return ((detail::TupleLeaf<I, Type> &)t.p_base).get();
}
template<Size I, typename ...A>
inline const TupleElement<I, Tuple<A...>> &get(const Tuple<A...> &t) {
using Type = TupleElement<I, Tuple<A...>>;
return ((const detail::TupleLeaf<I, Type> &)t.p_base).get();
}
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&t) {
using Type = TupleElement<I, Tuple<A...>>;
return ((detail::TupleLeaf<I, Type> &&)t.p_base).get();
}
/* tie */
template<typename ...T>
inline Tuple<T &...> tie(T &...t) {
return Tuple<T &...>(t...);
}
} /* namespace octa */
#endif

View File

@ -9,6 +9,7 @@
#include <stddef.h>
#include "octa/type_traits.hh"
#include "octa/internal/tuple.hh"
namespace octa {
@ -166,6 +167,69 @@ Pair<typename detail::MakePairRet<T>::Type,
>(forward<T>(a), forward<U>(b));;
}
template<typename T, typename U>
struct TupleSize<Pair<T, U>>: IntegralConstant<Size, 2> {};
template<typename T, typename U>
struct TupleSize<const Pair<T, U>>: IntegralConstant<Size, 2> {};
namespace detail {
template<typename T, typename U>
struct TupleElementBase<0, Pair<T, U>> {
using Type = T;
};
template<typename T, typename U>
struct TupleElementBase<1, Pair<T, U>> {
using Type = U;
};
template<typename T, typename U>
struct TupleElementBase<0, const Pair<T, U>> {
using Type = const T;
};
template<typename T, typename U>
struct TupleElementBase<1, const Pair<T, U>> {
using Type = const U;
};
template<Size> struct GetPair;
template<> struct GetPair<0> {
template<typename T, typename U>
static T &get(Pair<T, U> &p) { return p.first; }
template<typename T, typename U>
static const T &get(const Pair<T, U> &p) { return p.first; }
template<typename T, typename U>
static T &&get(Pair<T, U> &&p) { return forward<T>(p.first); }
};
template<> struct GetPair<1> {
template<typename T, typename U>
static U &get(Pair<T, U> &p) { return p.second; }
template<typename T, typename U>
static const U &get(const Pair<T, U> &p) { return p.second; }
template<typename T, typename U>
static U &&get(Pair<T, U> &&p) { return forward<U>(p.second); }
};
}
template<Size I, typename T, typename U>
TupleElement<I, Pair<T, U>> &get(Pair<T, U> &p) {
return detail::GetPair<I>::get(p);
}
template<Size I, typename T, typename U>
const TupleElement<I, Pair<T, U>> &get(const Pair<T, U> &p) {
return detail::GetPair<I>::get(p);
}
template<Size I, typename T, typename U>
TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&p) {
return detail::GetPair<I>::get(move(p));
}
namespace detail {
template<typename T, typename U,
bool = IsSame<RemoveCv<T>, RemoveCv<U>>::value,