forked from OSchip/llvm-project
[libc++] Add utilites for instantiating functions with multiple types
We currently call a lot of functions with the same list of types. To avoid forgetting any of them, this patch adds type_lists and utilities for it. Specifically, it adds - `type_list` - This is just a list of types - `concatenate` - This allows concatenating type_lists - `for_each` - Iterate over a type_list Reviewed By: ldionne, #libc Spies: jloser, EricWF, libcxx-commits Differential Revision: https://reviews.llvm.org/D137476
This commit is contained in:
parent
bd68070481
commit
1323461fe7
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
template <class In, class Out = In, class Sent = sentinel_wrapper<In>>
|
||||
concept HasCopyIt = requires(In in, Sent sent, Out out) { std::ranges::copy(in, sent, out); };
|
||||
|
@ -94,48 +95,28 @@ constexpr void test_iterators() {
|
|||
}
|
||||
}
|
||||
|
||||
template <class In, class Out>
|
||||
constexpr void test_sentinels() {
|
||||
test_iterators<In, Out>();
|
||||
test_iterators<In, Out, sized_sentinel<In>>();
|
||||
test_iterators<In, Out, sentinel_wrapper<In>>();
|
||||
}
|
||||
|
||||
template <class Out>
|
||||
constexpr void test_in_iterators() {
|
||||
test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
|
||||
test_sentinels<forward_iterator<int*>, Out>();
|
||||
test_sentinels<bidirectional_iterator<int*>, Out>();
|
||||
test_sentinels<random_access_iterator<int*>, Out>();
|
||||
test_sentinels<contiguous_iterator<int*>, Out>();
|
||||
}
|
||||
|
||||
template <class Out>
|
||||
constexpr void test_proxy_in_iterators() {
|
||||
test_iterators<ProxyIterator<cpp20_input_iterator<int*>>, Out, sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
|
||||
test_iterators<ProxyIterator<forward_iterator<int*>>, Out>();
|
||||
test_iterators<ProxyIterator<bidirectional_iterator<int*>>, Out>();
|
||||
test_iterators<ProxyIterator<random_access_iterator<int*>>, Out>();
|
||||
test_iterators<ProxyIterator<contiguous_iterator<int*>>, Out>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_in_iterators<cpp20_input_iterator<int*>>();
|
||||
test_in_iterators<forward_iterator<int*>>();
|
||||
test_in_iterators<bidirectional_iterator<int*>>();
|
||||
test_in_iterators<random_access_iterator<int*>>();
|
||||
test_in_iterators<contiguous_iterator<int*>>();
|
||||
meta::for_each(meta::forward_iterator_list<int*>{}, []<class Out>() {
|
||||
test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
|
||||
test_iterators<ProxyIterator<cpp20_input_iterator<int*>>,
|
||||
ProxyIterator<Out>,
|
||||
sentinel_wrapper<ProxyIterator<cpp20_input_iterator<int*>>>>();
|
||||
|
||||
test_proxy_in_iterators<ProxyIterator<cpp20_input_iterator<int*>>>();
|
||||
test_proxy_in_iterators<ProxyIterator<forward_iterator<int*>>>();
|
||||
test_proxy_in_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
|
||||
test_proxy_in_iterators<ProxyIterator<random_access_iterator<int*>>>();
|
||||
test_proxy_in_iterators<ProxyIterator<contiguous_iterator<int*>>>();
|
||||
meta::for_each(meta::forward_iterator_list<int*>{}, []<class In>() {
|
||||
test_iterators<In, Out>();
|
||||
test_iterators<In, Out, sized_sentinel<In>>();
|
||||
test_iterators<In, Out, sentinel_wrapper<In>>();
|
||||
|
||||
test_iterators<ProxyIterator<In>, ProxyIterator<Out>>();
|
||||
test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sized_sentinel<ProxyIterator<In>>>();
|
||||
test_iterators<ProxyIterator<In>, ProxyIterator<Out>, sentinel_wrapper<ProxyIterator<In>>>();
|
||||
});
|
||||
});
|
||||
|
||||
{ // check that ranges::dangling is returned
|
||||
std::array<int, 4> out;
|
||||
std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
|
||||
std::ranges::copy(std::array {1, 2, 3, 4}, out.data());
|
||||
std::ranges::copy(std::array{1, 2, 3, 4}, out.data());
|
||||
assert(ret.out == out.data() + 4);
|
||||
assert((out == std::array{1, 2, 3, 4}));
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
#include <limits>
|
||||
#include <complex>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
template <class T>
|
||||
void test()
|
||||
{
|
||||
struct Test {
|
||||
template <class T>
|
||||
void operator()() {
|
||||
static_assert(std::numeric_limits<T>::is_specialized,
|
||||
"std::numeric_limits<T>::is_specialized");
|
||||
static_assert(std::numeric_limits<const T>::is_specialized,
|
||||
|
@ -39,37 +39,15 @@ void test()
|
|||
"std::numeric_limits<volatile T>::is_specialized");
|
||||
static_assert(std::numeric_limits<const volatile T>::is_specialized,
|
||||
"std::numeric_limits<const volatile T>::is_specialized");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test<bool>();
|
||||
test<char>();
|
||||
test<wchar_t>();
|
||||
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
|
||||
test<char8_t>();
|
||||
#endif
|
||||
test<char16_t>();
|
||||
test<char32_t>();
|
||||
test<signed char>();
|
||||
test<unsigned char>();
|
||||
test<signed short>();
|
||||
test<unsigned short>();
|
||||
test<signed int>();
|
||||
test<unsigned int>();
|
||||
test<signed long>();
|
||||
test<unsigned long>();
|
||||
test<signed long long>();
|
||||
test<unsigned long long>();
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
test<__int128_t>();
|
||||
test<__uint128_t>();
|
||||
#endif
|
||||
test<float>();
|
||||
test<double>();
|
||||
test<long double>();
|
||||
static_assert(!std::numeric_limits<std::complex<double> >::is_specialized,
|
||||
"!std::numeric_limits<std::complex<double> >::is_specialized");
|
||||
meta::for_each(meta::arithmetic_types(), Test());
|
||||
|
||||
static_assert(!std::numeric_limits<std::complex<double> >::is_specialized,
|
||||
"!std::numeric_limits<std::complex<double> >::is_specialized");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
#include "min_allocator.h"
|
||||
|
||||
#include "make_string.h"
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
template <class S>
|
||||
TEST_CONSTEXPR_CXX20 void
|
||||
|
@ -57,17 +59,24 @@ test(S s, typename S::size_type pos)
|
|||
template <class S>
|
||||
TEST_CONSTEXPR_CXX20 void test_string() {
|
||||
test(S(), 0);
|
||||
test(S("123"), 0);
|
||||
test(S("123"), 1);
|
||||
test(S("123"), 2);
|
||||
test(S("123"), 3);
|
||||
test(S(MAKE_CSTRING(typename S::value_type, "123")), 0);
|
||||
test(S(MAKE_CSTRING(typename S::value_type, "123")), 1);
|
||||
test(S(MAKE_CSTRING(typename S::value_type, "123")), 2);
|
||||
test(S(MAKE_CSTRING(typename S::value_type, "123")), 3);
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test() {
|
||||
test_string<std::string>();
|
||||
struct TestCaller {
|
||||
template <class T>
|
||||
TEST_CONSTEXPR_CXX20 void operator()() {
|
||||
test_string<std::basic_string<T> >();
|
||||
#if TEST_STD_VER >= 11
|
||||
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
|
||||
test_string<std::basic_string<T, std::char_traits<T>, min_allocator<T> > >();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test() {
|
||||
meta::for_each(meta::character_types(), TestCaller());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
// concatenate
|
||||
static_assert(std::is_same<meta::concatenate_t<meta::type_list<> >, meta::type_list<> >::value, "");
|
||||
static_assert(std::is_same<meta::concatenate_t<meta::type_list<int> >, meta::type_list<int> >::value, "");
|
||||
static_assert(
|
||||
std::is_same<meta::concatenate_t<meta::type_list<int>, meta::type_list<long> >, meta::type_list<int, long> >::value,
|
||||
"");
|
||||
static_assert(
|
||||
std::is_same<meta::concatenate_t<meta::type_list<int>, meta::type_list<long>, meta::type_list<long long> >,
|
||||
meta::type_list<int, long, long long> >::value,
|
||||
"");
|
||||
|
||||
// apply_all
|
||||
template <int N>
|
||||
class NumT {};
|
||||
|
||||
struct ApplyAllTest {
|
||||
bool* is_called_array_;
|
||||
|
||||
TEST_CONSTEXPR ApplyAllTest(bool* is_called_array) : is_called_array_(is_called_array) {}
|
||||
|
||||
template <int N>
|
||||
TEST_CONSTEXPR_CXX20 void check_num(NumT<N>) {
|
||||
assert(!is_called_array_[N]);
|
||||
is_called_array_[N] = true;
|
||||
}
|
||||
|
||||
template <int N, int M>
|
||||
TEST_CONSTEXPR_CXX20 void check_num(NumT<N>, NumT<M>) {
|
||||
assert(!is_called_array_[N + M]);
|
||||
is_called_array_[N + M] = true;
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
TEST_CONSTEXPR_CXX20 void operator()() {
|
||||
check_num(Types()...);
|
||||
}
|
||||
};
|
||||
|
||||
struct Identity {
|
||||
TEST_CONSTEXPR bool operator()(bool b) const { return b; }
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 void test_for_each() {
|
||||
bool is_called_array[3] = {};
|
||||
meta::for_each(meta::type_list<NumT<0>, NumT<1>, NumT<2> >(), ApplyAllTest(is_called_array));
|
||||
assert(std::all_of(is_called_array, is_called_array + 3, Identity()));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test() {
|
||||
test_for_each();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
|
||||
// This iterator meets C++20's Cpp17OutputIterator requirements, as described
|
||||
|
@ -1297,6 +1298,23 @@ template <std::ranges::input_range R>
|
|||
requires std::ranges::viewable_range<R&&>
|
||||
ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
|
||||
|
||||
namespace meta {
|
||||
template <class Ptr>
|
||||
using random_access_iterator_list = type_list<Ptr, contiguous_iterator<Ptr>, random_access_iterator<Ptr>>;
|
||||
|
||||
template <class Ptr>
|
||||
using bidirectional_iterator_list =
|
||||
concatenate_t<random_access_iterator_list<Ptr>, type_list<bidirectional_iterator<Ptr>>>;
|
||||
|
||||
template <class Ptr>
|
||||
using forward_iterator_list = concatenate_t<bidirectional_iterator_list<Ptr>, type_list<forward_iterator<Ptr>>>;
|
||||
|
||||
template <class Ptr>
|
||||
using cpp20_input_iterator_list =
|
||||
concatenate_t<forward_iterator_list<Ptr>, type_list<cpp20_input_iterator<Ptr>, cpp17_input_iterator<Ptr>>>;
|
||||
|
||||
} // namespace meta
|
||||
|
||||
#endif // TEST_STD_VER > 17
|
||||
|
||||
#endif // SUPPORT_TEST_ITERATORS_H
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TEST_SUPPORT_TYPE_ALGORITHMS_H
|
||||
#define TEST_SUPPORT_TYPE_ALGORITHMS_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace meta {
|
||||
template <class... Types>
|
||||
struct type_list {};
|
||||
|
||||
// concatenates N type_lists to one (for N >= 1)
|
||||
template <class...>
|
||||
struct concatenate;
|
||||
|
||||
template <class... Types>
|
||||
using concatenate_t = typename concatenate<Types...>::type;
|
||||
|
||||
// for_each takes a type_list calls f with each element as the first template argument
|
||||
template <class... Types, class Functor>
|
||||
TEST_CONSTEXPR_CXX14 void for_each(type_list<Types...>, Functor f);
|
||||
|
||||
// impl
|
||||
template <class... Types>
|
||||
struct concatenate<type_list<Types...> > {
|
||||
using type = type_list<Types...>;
|
||||
};
|
||||
|
||||
template <class... Types1, class... Types2>
|
||||
struct concatenate<type_list<Types1...>, type_list<Types2...> > {
|
||||
using type = type_list<Types1..., Types2...>;
|
||||
};
|
||||
|
||||
template <class... Types1, class... Types2, class... Rest>
|
||||
struct concatenate<type_list<Types1...>, type_list<Types2...>, Rest...> {
|
||||
using type = concatenate_t<type_list<Types1..., Types2...>, Rest...>;
|
||||
};
|
||||
|
||||
template <class... Types>
|
||||
TEST_CONSTEXPR_CXX14 void swallow(Types...) {}
|
||||
|
||||
template <class... Types, class Functor>
|
||||
TEST_CONSTEXPR_CXX14 void for_each(type_list<Types...>, Functor f) {
|
||||
swallow((f.template operator()<Types>(), 0)...);
|
||||
}
|
||||
|
||||
// type categories defined in [basic.fundamental] plus extensions (without CV-qualifiers)
|
||||
|
||||
using character_types =
|
||||
type_list<char
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
,
|
||||
wchar_t
|
||||
#endif
|
||||
#ifndef TEST_HAS_NO_CHAR8_T
|
||||
,
|
||||
char8_t
|
||||
#endif
|
||||
#if TEST_STD_VER >= 11
|
||||
,
|
||||
char16_t,
|
||||
char32_t
|
||||
#endif
|
||||
>;
|
||||
|
||||
using signed_integer_types =
|
||||
type_list<signed char,
|
||||
short,
|
||||
int,
|
||||
long,
|
||||
long long
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
,
|
||||
__int128_t
|
||||
#endif
|
||||
>;
|
||||
|
||||
using unsigned_integer_types =
|
||||
type_list<unsigned char,
|
||||
unsigned short,
|
||||
unsigned int,
|
||||
unsigned long,
|
||||
unsigned long long
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
,
|
||||
__uint128_t
|
||||
#endif
|
||||
>;
|
||||
|
||||
using integral_types = concatenate_t<character_types, signed_integer_types, unsigned_integer_types, type_list<bool> >;
|
||||
|
||||
using floating_point_types = type_list<float, double, long double>;
|
||||
|
||||
using arithmetic_types = concatenate_t<integral_types, floating_point_types>;
|
||||
} // namespace meta
|
||||
|
||||
#endif // TEST_SUPPORT_TYPE_ALGORITHMS_H
|
Loading…
Reference in New Issue