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 <stddef.h>
|
||||||
|
|
||||||
#include "octa/type_traits.hh"
|
#include "octa/type_traits.hh"
|
||||||
|
#include "octa/internal/tuple.hh"
|
||||||
|
|
||||||
namespace octa {
|
namespace octa {
|
||||||
|
|
||||||
|
@ -166,6 +167,69 @@ Pair<typename detail::MakePairRet<T>::Type,
|
||||||
>(forward<T>(a), forward<U>(b));;
|
>(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 {
|
namespace detail {
|
||||||
template<typename T, typename U,
|
template<typename T, typename U,
|
||||||
bool = IsSame<RemoveCv<T>, RemoveCv<U>>::value,
|
bool = IsSame<RemoveCv<T>, RemoveCv<U>>::value,
|
||||||
|
|
Loading…
Reference in a new issue