initial implementation of tuples
This commit is contained in:
parent
3fd83c4bbd
commit
b496d130ab
282
octa/internal/tuple.hh
Normal file
282
octa/internal/tuple.hh
Normal 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
Normal file
444
octa/tuple.hh
Normal 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
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue