4#ifndef TUPLET_TUPLET_HPP_IMPLEMENTATION
5#define TUPLET_TUPLET_HPP_IMPLEMENTATION
20#define TUPLET_INLINE __forceinline
21#elif __GNUC__ || __clang__
22#define TUPLET_INLINE [[gnu::always_inline]]
28#define _TUPLET_COMPARISON_OPERATOR_1(type, member, op) \
29 TUPLET_INLINE constexpr auto operator op(type const& other) const noexcept(noexcept(member op other.member)) \
31 return member op other.member; \
36#define TUPLET_FWD_M(TupleType, BaseType, tup, value) \
37 static_cast<::tuplet::forward_as_t<TupleType&&, BaseType>>(tup).value
39#define TUPLET_GET_M(BaseType, tup, value) tup.::tuplet::identity_t<BaseType>::value
42#define TUPLET_FWD_M(TupleType, BaseType, tup, value) \
43 static_cast<TupleType&&>(tup).::tuplet::identity_t<BaseType>::value
44#define TUPLET_GET_M(BaseType, tup, value) tup.::tuplet::identity_t<BaseType>::value
47#define TUPLET_FWD_M(TupleType, BaseType, tup, value) static_cast<TupleType&&>(tup).BaseType::value
48#define TUPLET_GET_M(BaseType, tup, value) tup.BaseType::value
51#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison && !defined(TUPLET_DEFAULTED_COMPARISON)
52#define TUPLET_DEFAULTED_COMPARISON 1
55#define TUPLET_DEFAULTED_COMPARISON 0
59#define TUPLET_OTHER_THAN(Self, Other) tuplet::other_than<Self> Other
60#define TUPLET_WEAK_CONCEPT(...) __VA_ARGS__
61#define TUPLET_WEAK_REQUIRES(...) requires __VA_ARGS__
62#define _TUPLET_TYPES_EQ_WITH(T, U) \
64 requires(::tuplet::equality_comparable_with<T, U> && ...)
65#define _TUPLET_TYPES_CMP_WITH(T, U) \
67 requires(::tuplet::equality_comparable_with<T, U> && ...)
69#define TUPLET_OTHER_THAN(Self, Other) class Other, class = ::tuplet::sfinae::other_than<Self, Other>
70#define TUPLET_WEAK_CONCEPT(...) class
71#define TUPLET_WEAK_REQUIRES(...)
73#define _TUPLET_TYPES_EQ_WITH(T, U) \
74 ::std::enable_if_t<::tuplet::sfinae::detail::_all_true<::tuplet::sfinae::detail::_has_eq<T, U>...>(), bool>
75#define _TUPLET_TYPES_CMP_WITH(T, U) \
76 ::std::enable_if_t<::tuplet::sfinae::detail::_all_true<::tuplet::sfinae::detail::_has_cmp<T, U>...>(), bool>
78#define _TUPLET_TYPES_EQ_WITH(T, U) ::std::enable_if_t<((::tuplet::sfinae::detail::_has_eq<T, U>) && ...), bool>
79#define _TUPLET_TYPES_CMP_WITH(T, U) ::std::enable_if_t<((::tuplet::sfinae::detail::_has_cmp<T, U>) && ...), bool>
83#if defined(TUPLET_NO_UNIQUE_ADDRESS) && !TUPLET_NO_UNIQUE_ADDRESS
84#define TUPLET_NO_UNIQUE_ADDRESS
86#if _MSVC_LANG >= 202002L && (!defined __clang__)
88#define TUPLET_HAS_NO_UNIQUE_ADDRESS 1
89#define TUPLET_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
93#define TUPLET_HAS_NO_UNIQUE_ADDRESS 0
94#define TUPLET_NO_UNIQUE_ADDRESS
96#elif __cplusplus > 201703L && (__has_cpp_attribute(no_unique_address))
98#define TUPLET_HAS_NO_UNIQUE_ADDRESS 1
99#define TUPLET_NO_UNIQUE_ADDRESS [[no_unique_address]]
103#define TUPLET_HAS_NO_UNIQUE_ADDRESS 0
104#define TUPLET_NO_UNIQUE_ADDRESS
133template <
class T,
class U>
constexpr bool _test_eq(
long long)
143template <
class T,
class U>
constexpr bool _test_less(
long long)
152template <
class Tup,
class =
typename Tup::base_list>
constexpr bool _has_base_list(
int)
169 for (
bool b : values) {
179 for (
bool b : values) {
251template <
class Tup,
class B>
using forward_as_t = typename ::tuplet::detail::_forward_as<Tup, B>::type;
256template <
class T>
using type_t =
typename T::type;
264template <
class Tup>
using base_list_t =
typename std::decay_t<Tup>::base_list;
265template <
class Tup>
using element_list_t =
typename std::decay_t<Tup>::element_list;
270template <
class T,
class U>
273template <
class T,
class U>
276template <
class Tuple>
277concept base_list_tuple =
requires() {
typename std::decay_t<Tuple>::base_list; };
285template <
class U,
class T>
289concept ordered =
requires(T
const& t) {
293template <
class T,
class U>
302template <
class T,
class U>
311template <
class T,
class U>
319template <
class Tuple>
324 tuplet::sfinae::detail::_has_base_list<Tuple>(0);
337 if constexpr (::tuplet::sfinae::detail::_test_m_compare<T, U>(0)) {
338 int cmp =
a.compare(
b);
345#if TUPLET_DEFAULTED_COMPARISON
375 return [&](
auto&...
v1) ->
bool {
387 [&](
auto&...
v1) ->
bool {
401 bool is_eq = [&](
auto&...
v1) ->
bool {
411template <
class Tup1,
class Tup2,
class...
B1,
class...
B2>
415 return [&](
auto&...
v1) ->
bool {
423template <
class Tup1,
class Tup2,
class...
B1,
class...
B2>
428 [&](
auto&...
v1) ->
bool {
438template <
class Tup1,
class Tup2,
class...
B1,
class...
B2>
443 bool is_eq = [&](
auto&...
v1) ->
bool {
459template <
class... Bases>
struct type_map : Bases... {
461 using Bases::operator[]...;
462 using Bases::decl_elem...;
464#if TUPLET_DEFAULTED_COMPARISON
508#if TUPLET_DEFAULTED_COMPARISON
517 TUPLET_INLINE constexpr bool operator==(tuple_elem
const& other)
const noexcept(
noexcept(
value == other.value))
520 return value == other.value;
556template <
class... T>
struct tuple;
568 return [&](
auto&&...
v1) ->
bool {
579 return [&](
auto&&...
v1) ->
bool {
587template <
class Tup,
class F,
class...
B>
611 constexpr static size_t N =
sizeof...(T);
612 constexpr static bool
614 nothrow_swappable = ::tuplet::sfinae::detail::_all_true<std::is_nothrow_swappable_v<T>...>();
619 using super::operator[];
622 using super::decl_elem;
624 template <TUPLET_OTHER_THAN(tuple, U)>
642#if TUPLET_DEFAULTED_COMPARISON
673 template <
class...
U>
679 template <
class...
U>
682 return !(*
this == other);
684 template <
class...
U>
690 template <
class...
U>
696 template <
class...
U>
702 template <
class...
U>
790 static_assert(
sizeof...(U) ==
N,
"Can only convert to tuples with the same number of items");
795 static_assert(
sizeof...(U) ==
N,
"Can only convert to tuples with the same number of items");
800 static_assert(
sizeof...(U) ==
N,
"Can only convert to tuples with the same number of items");
811 return detail::_convert<U>(
static_cast<tuple&&
>(*
this),
base_list{});
821 template <
class U,
class...
B1,
class...
B2>
836 (
void(B::value =
static_cast<U&&
>(
u)), ...);
847 constexpr static size_t N = 0;
853 template <TUPLET_OTHER_THAN(tuple, U)>
863#if TUPLET_DEFAULTED_COMPARISON
902 template <
class F>
constexpr decltype(
auto)
apply(
F&&
func)
const noexcept {
return func(); }
914template <
class First,
class Second>
struct pair {
915 constexpr static size_t N = 2;
934 template <TUPLET_OTHER_THAN(pair, Type)>
937 auto&& [
a,
b] =
static_cast<Type&&
>(
tup);
943 template <TUPLET_WEAK_CONCEPT(assignable_to<First>) F2, TUPLET_WEAK_CONCEPT(assignable_to<Second>) S2>
951#if TUPLET_DEFAULTED_COMPARISON
971 return result ||
is_eq;
984 return result ||
is_eq;
998 using base_list =
typename std::decay_t<Tuple>::base_list;
1000 template <
class U>
constexpr operator U() &&
1031template <
class F, TUPLET_WEAK_CONCEPT(base_list_tuple) Tup>
1040template <
class F,
class A,
class B>
1048 return static_cast<F&&
>(
func)(
static_cast<P>(
pair).first,
static_cast<P>(
pair).second);
1056template <
class A,
class B>
1069 return tuple<T&&...>{
static_cast<T&&
>(
a)... };
1093template <
class T,
class...
Outer,
class...
Inner>
1103 if constexpr (
sizeof...(T) == 0) {
1116#if !defined(TUPLET_CAT_BY_FORWARDING_TUPLE)
1117#if defined(__clang__)
1118#define TUPLET_CAT_BY_FORWARDING_TUPLE 0
1120#define TUPLET_CAT_BY_FORWARDING_TUPLE 1
1123#if TUPLET_CAT_BY_FORWARDING_TUPLE
1144 static_assert(((
'0' <=
D &&
D <=
'9') && ...),
"Must be integral literal");
1146 return ((
num =
num * 10 + (
D -
'0')), ...,
num);
1151template <
char...
D>
constexpr auto operator""_tag()
noexcept ->
tag<detail::_size_t_from_digits<
D...>()>
1162template <
class... T>
struct tuple_size<
tuplet::tuple<T...>> : std::integral_constant<size_t, sizeof...(T)> {};
1167template <
class A,
class B>
struct tuple_size<
tuplet::pair<A, B>> : std::integral_constant<size_t, 2> {};
1170 static_assert(
I < 2,
"tuplet::pair only has 2 elements");
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
TUPLET_INLINE constexpr bool _any(Tup &&tup, F &&func, type_list< B... >)
TUPLET_INLINE constexpr bool _all(Tup &&tup, F &&func, type_list< B... >)
TUPLET_INLINE constexpr auto _get_outer_bases(type_list< Outer... >)
TUPLET_INLINE constexpr void _for_each(Tup &&tup, F &&func, type_list< B... >)
TUPLET_INLINE constexpr bool _equals(Tup const &t1, Tup const &t2, type_list< B1... >)
TUPLET_INLINE constexpr auto _get_inner_bases(type_list< Outer... >)
TUPLET_INLINE constexpr bool _less(Tup const &t1, Tup const &t2, type_list< B1... >)
TUPLET_INLINE constexpr decltype(auto) _apply(Tup &&t, F &&f, type_list< B... >)
TUPLET_INLINE constexpr bool _partial_cmp(T const &a, U const &b, bool &less)
TUPLET_INLINE constexpr bool _less_eq(Tup const &t1, Tup const &t2, type_list< B1... >)
TUPLET_INLINE constexpr auto _map(Tup &&tup, F &&func, type_list< B... >) -> tuple< decltype(func(TUPLET_FWD_M(Tup, B, tup, value)))... >
TUPLET_INLINE constexpr auto _tuple_cat(T tup, type_list< Outer... >, type_list< Inner... >) -> tuple< type_t< Inner >... >
TUPLET_INLINE constexpr auto _repeat_type(type_list< Q... >)
TUPLET_INLINE constexpr U _convert(Tup &&t, type_list< B... >)
constexpr size_t _size_t_from_digits()
constexpr bool _test_m_compare(int)
constexpr bool _test_eq(int)
constexpr bool _all_has_eq(type_list< T... >, type_list< U... >)
constexpr bool _test_less(int)
constexpr bool _all_has_cmp(type_list< T... >, type_list< U... >)
constexpr bool _has_base_list(int)
constexpr bool _all_true()
std::enable_if_t<!std::is_same_v< std::decay_t< A >, std::decay_t< B > > > other_than
Implement assignment but preserve default assignment.
TUPLET_INLINE void swap(tuple< T... > &a, tuple< T... > &b) noexcept(tuple< T... >::nothrow_swappable)
constexpr bool stateless_v
TUPLET_INLINE constexpr tuple< T &... > tie(T &... t)
constexpr auto base_list_tuple_v
std::integral_constant< size_t, I > tag
typename unwrap_ref_decay< T >::type unwrap_ref_decay_t
TUPLET_INLINE constexpr auto forward_as_tuple(T &&... a) noexcept
TUPLET_INLINE constexpr auto make_tuple(Ts &&... args)
std::make_index_sequence< N > tag_range
constexpr auto tuple_cat(T &&... ts)
TUPLET_INLINE constexpr auto operator+(type_list< Ls... >, type_list< Rs... >)
Convinience + operator for catenating type lists.
typename std::decay_t< Tup >::element_list element_list_t
typename ::tuplet::detail::_forward_as< Tup, B >::type forward_as_t
TUPLET_INLINE constexpr decltype(auto) get(Tup &&tup)
typename std::decay_t< Tup >::base_list base_list_t
typename detail::_get_tuple_base< tag_range< sizeof...(T)>, T... >::type tuple_base_t
TUPLET_INLINE constexpr decltype(auto) apply(F &&func, Tup &&tup)
std::conditional_t< I==0, A, B > type
decltype(tuplet::tuple< T... >::decl_elem(tuplet::tag< I >())) type
typename std::decay_t< Tuple >::base_list base_list
TUPLET_INLINE constexpr auto & operator=(Type &&tup)
static constexpr bool nothrow_swappable
TUPLET_INLINE constexpr auto & assign(F2 &&f, S2 &&s)
TUPLET_INLINE constexpr bool operator!=(pair const &other) const
TUPLET_INLINE constexpr bool operator<(pair const &other) const
TUPLET_INLINE constexpr bool operator<=(pair const &other) const
static constexpr size_t N
TUPLET_INLINE void swap(pair &other) noexcept(nothrow_swappable)
TUPLET_INLINE constexpr bool operator>(pair const &other) const
TUPLET_NO_UNIQUE_ADDRESS First first
TUPLET_INLINE constexpr bool operator==(pair const &other) const
TUPLET_INLINE constexpr bool operator>=(pair const &other) const
TUPLET_NO_UNIQUE_ADDRESS Second second
constexpr auto & assign() noexcept
TUPLET_INLINE constexpr bool operator>(tuple const &) const noexcept
constexpr auto map(F &&) const noexcept
constexpr auto & operator=(U &&) noexcept
constexpr bool all(F &&) const noexcept
constexpr U as() const noexcept
TUPLET_INLINE constexpr bool operator<(tuple const &) const noexcept
constexpr bool any(F &&) const noexcept
constexpr decltype(auto) apply(F &&func) const noexcept
constexpr void swap(tuple) noexcept
TUPLET_INLINE constexpr bool operator>=(tuple const &) const noexcept
TUPLET_INLINE constexpr bool operator<=(tuple const &) const noexcept
TUPLET_INLINE constexpr bool operator==(tuple const &) const noexcept
constexpr void for_each(F &&) const noexcept
TUPLET_INLINE constexpr bool operator!=(tuple const &) const noexcept
static T decl_elem(tag< I >)
TUPLET_NO_UNIQUE_ADDRESS T value
TUPLET_INLINE constexpr auto operator>(tuple< U... > const &other) const -> _TUPLET_TYPES_CMP_WITH(T, U)
TUPLET_WEAK_REQUIRES((assignable_to< U, T > &&...)) const expr auto &assign(U &&... values)
TUPLET_INLINE constexpr U as() &
Instantiate the given type using list initialization.
TUPLET_INLINE constexpr bool all(F &&func) &
TUPLET_INLINE constexpr auto operator<(tuple< U... > const &other) const -> _TUPLET_TYPES_CMP_WITH(T, U)
TUPLET_INLINE constexpr decltype(auto) apply(F &&func) &
TUPLET_INLINE constexpr void swap(tuple &other) noexcept(nothrow_swappable)
TUPLET_INLINE constexpr bool all(F &&func) const &
TUPLET_INLINE constexpr void _assign_index_tup(U &&u, std::index_sequence< I... >)
TUPLET_INLINE constexpr void for_each(F &&func) const &
TUPLET_INLINE constexpr decltype(auto) apply(F &&func) const &
TUPLET_INLINE constexpr auto operator>(tuple const &other) const
TUPLET_INLINE constexpr decltype(auto) apply(F &&func) &&
TUPLET_INLINE constexpr auto operator>=(tuple< U... > const &other) const -> _TUPLET_TYPES_CMP_WITH(T, U)
TUPLET_INLINE constexpr void for_each(F &&func) &
static constexpr bool nothrow_swappable
tuple_base_t< T... > super
TUPLET_INLINE constexpr bool any(F &&func) const &
TUPLET_INLINE constexpr auto operator<(tuple const &other) const
TUPLET_INLINE constexpr void _assign_tup(U &&u, type_list< B1... >, type_list< B2... >)
TUPLET_INLINE constexpr U as() const &
Instantiate the given type using list initialization.
typename super::base_list base_list
TUPLET_INLINE constexpr void for_each(F &&func) &&
TUPLET_INLINE constexpr auto operator>=(tuple const &other) const
TUPLET_INLINE constexpr U as() &&
Instantiate the given type using list initialization.
TUPLET_INLINE constexpr auto map(F &&func) &&
TUPLET_INLINE constexpr auto operator!=(tuple< U... > const &other) const -> _TUPLET_TYPES_EQ_WITH(T, U)
TUPLET_INLINE constexpr auto operator<=(tuple const &other) const
TUPLET_INLINE constexpr bool any(F &&func) &&
TUPLET_INLINE constexpr auto & operator=(U &&tup)
TUPLET_INLINE constexpr auto operator==(tuple const &other) const
TUPLET_INLINE constexpr auto operator==(tuple< U... > const &other) const -> _TUPLET_TYPES_EQ_WITH(T, U)
static constexpr size_t N
TUPLET_INLINE constexpr void _assign(type_list< B... >, U &&... u)
TUPLET_INLINE constexpr auto operator<=(tuple< U... > const &other) const -> _TUPLET_TYPES_CMP_WITH(T, U)
TUPLET_INLINE constexpr bool any(F &&func) &
TUPLET_INLINE constexpr auto operator!=(tuple const &other) const
TUPLET_INLINE constexpr auto map(F &&func) &
TUPLET_INLINE constexpr void _swap(tuple &other, type_list< B... >) noexcept(nothrow_swappable)
TUPLET_INLINE constexpr bool all(F &&func) &&
TUPLET_INLINE constexpr auto map(F &&func) const &
Represents a list of types.
TUPLET_INLINE constexpr auto operator>=(type_map const &other) const
TUPLET_INLINE constexpr auto operator<(type_map const &other) const
TUPLET_INLINE constexpr auto operator<=(type_map const &other) const
TUPLET_INLINE constexpr auto operator==(type_map const &other) const
TUPLET_INLINE constexpr auto operator!=(type_map const &other) const
TUPLET_INLINE constexpr auto operator>(type_map const &other) const
#define _TUPLET_TYPES_EQ_WITH(T, U)
#define TUPLET_FWD_M(TupleType, BaseType, tup, value)
Looks up a member in a tuple via the base class, and forwards it.
#define TUPLET_WEAK_CONCEPT(...)
#define TUPLET_NO_UNIQUE_ADDRESS
#define _TUPLET_COMPARISON_OPERATOR_1(type, member, op)
#define TUPLET_GET_M(BaseType, tup, value)
#define TUPLET_WEAK_REQUIRES(...)
#define _TUPLET_TYPES_CMP_WITH(T, U)