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
#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); };
}
}
-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*>>();
-
- 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 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*>>>>();
+
+ 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}));
}
#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,
"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;
}
#include "min_allocator.h"
+#include "make_string.h"
#include "test_macros.h"
+#include "type_algorithms.h"
template <class S>
TEST_CONSTEXPR_CXX20 void
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;
}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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;
+}
#include <utility>
#include "test_macros.h"
+#include "type_algorithms.h"
// This iterator meets C++20's Cpp17OutputIterator requirements, as described
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
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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