diff options
Diffstat (limited to 'libc/src/__support/CPP')
| -rw-r--r-- | libc/src/__support/CPP/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | libc/src/__support/CPP/algorithm.h | 6 | ||||
| -rw-r--r-- | libc/src/__support/CPP/bit.h | 22 | ||||
| -rw-r--r-- | libc/src/__support/CPP/simd.h | 282 | ||||
| -rw-r--r-- | libc/src/__support/CPP/tuple.h | 144 | ||||
| -rw-r--r-- | libc/src/__support/CPP/type_traits/is_complex.h | 7 | ||||
| -rw-r--r-- | libc/src/__support/CPP/utility/integer_sequence.h | 10 |
7 files changed, 484 insertions, 2 deletions
diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt index 8b65a8839ab2..d9b86b4fd297 100644 --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -171,6 +171,7 @@ add_header_library( libc.include.llvm-libc-macros.stdfix_macros libc.src.__support.macros.attributes libc.src.__support.macros.properties.types + libc.src.__support.macros.properties.compiler libc.src.__support.macros.properties.complex_types ) @@ -210,3 +211,17 @@ add_object_library( libc.src.__support.common libc.src.__support.macros.properties.os ) + +add_header_library( + tuple + HDRS + tuple.h + DEPENDS + .utility +) + +add_header_library( + simd + HDRS + simd.h +) diff --git a/libc/src/__support/CPP/algorithm.h b/libc/src/__support/CPP/algorithm.h index 7704b3fa81f0..de0c47369d94 100644 --- a/libc/src/__support/CPP/algorithm.h +++ b/libc/src/__support/CPP/algorithm.h @@ -18,6 +18,12 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { +template <class T = void> struct plus {}; +template <class T = void> struct multiplies {}; +template <class T = void> struct bit_and {}; +template <class T = void> struct bit_or {}; +template <class T = void> struct bit_xor {}; + template <class T> LIBC_INLINE constexpr const T &max(const T &a, const T &b) { return (a < b) ? b : a; } diff --git a/libc/src/__support/CPP/bit.h b/libc/src/__support/CPP/bit.h index df1b177ecb10..5a997ef55570 100644 --- a/libc/src/__support/CPP/bit.h +++ b/libc/src/__support/CPP/bit.h @@ -104,10 +104,16 @@ countr_zero(T value) { } #if __has_builtin(__builtin_ctzs) ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs) -#endif +#endif // __has_builtin(__builtin_ctzs) +#if __has_builtin(__builtin_ctz) ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz) +#endif // __has_builtin(__builtin_ctz) +#if __has_builtin(__builtin_ctzl) ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl) +#endif // __has_builtin(__builtin_ctzl) +#if __has_builtin(__builtin_ctzll) ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll) +#endif // __has_builtin(__builtin_ctzll) #endif // __has_builtin(__builtin_ctzg) /// Count number of 0's from the most significant bit to the least @@ -143,10 +149,16 @@ countl_zero(T value) { } #if __has_builtin(__builtin_clzs) ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs) -#endif +#endif // __has_builtin(__builtin_clzs) +#if __has_builtin(__builtin_clz) ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz) +#endif // __has_builtin(__builtin_clz) +#if __has_builtin(__builtin_clzl) ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl) +#endif // __has_builtin(__builtin_clzl) +#if __has_builtin(__builtin_clzll) ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll) +#endif // __has_builtin(__builtin_clzll) #endif // __has_builtin(__builtin_clzg) #undef ADD_SPECIALIZATION @@ -283,11 +295,17 @@ popcount(T value) { [[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \ return BUILTIN(value); \ } +#if __has_builtin(__builtin_popcount) ADD_SPECIALIZATION(unsigned char, __builtin_popcount) ADD_SPECIALIZATION(unsigned short, __builtin_popcount) ADD_SPECIALIZATION(unsigned, __builtin_popcount) +#endif // __builtin_popcount +#if __has_builtin(__builtin_popcountl) ADD_SPECIALIZATION(unsigned long, __builtin_popcountl) +#endif // __builtin_popcountl +#if __has_builtin(__builtin_popcountll) ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll) +#endif // __builtin_popcountll #endif // __builtin_popcountg #undef ADD_SPECIALIZATION diff --git a/libc/src/__support/CPP/simd.h b/libc/src/__support/CPP/simd.h new file mode 100644 index 000000000000..54fe70a6e983 --- /dev/null +++ b/libc/src/__support/CPP/simd.h @@ -0,0 +1,282 @@ +//===-- Portable SIMD library similar to stdx::simd -------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides a generic interface into fixed-size SIMD instructions +// using the clang vector type. The API shares some similarities with the +// stdx::simd proposal, but instead chooses to use vectors as primitive types +// with several extra helper functions. +// +//===----------------------------------------------------------------------===// + +#include "hdr/stdint_proxy.h" +#include "src/__support/CPP/algorithm.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_SIMD_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_SIMD_H + +#if LIBC_HAS_VECTOR_TYPE + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +namespace internal { + +template <typename T> +using get_as_integer_type_t = unsigned _BitInt(sizeof(T) * CHAR_BIT); + +#if defined(LIBC_TARGET_CPU_HAS_AVX512F) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 64 / sizeof(T); +#elif defined(LIBC_TARGET_CPU_HAS_AVX2) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 32 / sizeof(T); +#elif defined(LIBC_TARGET_CPU_HAS_SSE2) || defined(LIBC_TARGET_CPU_HAS_ARM_NEON) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 16 / sizeof(T); +#else +template <typename T> LIBC_INLINE constexpr size_t native_vector_size = 1; +#endif + +template <typename T> LIBC_INLINE constexpr T poison() { + return __builtin_nondeterministic_value(T()); +} +} // namespace internal + +// Type aliases. +template <typename T, size_t N> +using fixed_size_simd = T [[clang::ext_vector_type(N)]]; +template <typename T, size_t N = internal::native_vector_size<T>> +using simd = T [[clang::ext_vector_type(N)]]; +template <typename T> +using simd_mask = simd<bool, internal::native_vector_size<T>>; + +// Type trait helpers. +template <typename T> +struct simd_size : cpp::integral_constant<size_t, __builtin_vectorelements(T)> { +}; +template <class T> constexpr size_t simd_size_v = simd_size<T>::value; + +template <typename T> struct is_simd : cpp::integral_constant<bool, false> {}; +template <typename T, unsigned N> +struct is_simd<simd<T, N>> : cpp::integral_constant<bool, true> {}; +template <class T> constexpr bool is_simd_v = is_simd<T>::value; + +template <typename T> +struct is_simd_mask : cpp::integral_constant<bool, false> {}; +template <unsigned N> +struct is_simd_mask<simd<bool, N>> : cpp::integral_constant<bool, true> {}; +template <class T> constexpr bool is_simd_mask_v = is_simd_mask<T>::value; + +template <typename T> struct simd_element_type; +template <typename T, size_t N> struct simd_element_type<simd<T, N>> { + using type = T; +}; +template <typename T> +using simd_element_type_t = typename simd_element_type<T>::type; + +template <typename T> +using enable_if_simd_t = cpp::enable_if_t<is_simd_v<T>, T>; + +// Casting. +template <typename To, typename From, size_t N> +LIBC_INLINE constexpr static simd<To, N> simd_cast(simd<From, N> v) { + return __builtin_convertvector(v, simd<To, N>); +} + +// SIMD mask operations. +template <size_t N> LIBC_INLINE constexpr static bool all_of(simd<bool, N> m) { + return __builtin_reduce_and(m); +} +template <size_t N> LIBC_INLINE constexpr static bool any_of(simd<bool, N> m) { + return __builtin_reduce_or(m); +} +template <size_t N> LIBC_INLINE constexpr static bool none_of(simd<bool, N> m) { + return !any_of(m); +} +template <size_t N> LIBC_INLINE constexpr static bool some_of(simd<bool, N> m) { + return any_of(m) && !all_of(m); +} +template <size_t N> LIBC_INLINE constexpr static int popcount(simd<bool, N> m) { + return __builtin_popcountg(m); +} +template <size_t N> +LIBC_INLINE constexpr static int find_first_set(simd<bool, N> m) { + return __builtin_ctzg(m); +} +template <size_t N> +LIBC_INLINE constexpr static int find_last_set(simd<bool, N> m) { + constexpr size_t size = simd_size_v<simd<bool, N>>; + return size - 1 - __builtin_clzg(m); +} + +// Elementwise operations. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> min(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_min(x, y); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> max(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_max(x, y); +} + +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> abs(simd<T, N> x) { + return __builtin_elementwise_abs(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> fma(simd<T, N> x, simd<T, N> y, + simd<T, N> z) { + return __builtin_elementwise_fma(x, y, z); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> ceil(simd<T, N> x) { + return __builtin_elementwise_ceil(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> floor(simd<T, N> x) { + return __builtin_elementwise_floor(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> roundeven(simd<T, N> x) { + return __builtin_elementwise_roundeven(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> round(simd<T, N> x) { + return __builtin_elementwise_round(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> trunc(simd<T, N> x) { + return __builtin_elementwise_trunc(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> nearbyint(simd<T, N> x) { + return __builtin_elementwise_nearbyint(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> rint(simd<T, N> x) { + return __builtin_elementwise_rint(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> canonicalize(simd<T, N> x) { + return __builtin_elementwise_canonicalize(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> copysign(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_copysign(x, y); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> fmod(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_fmod(x, y); +} + +// Reduction operations. +template <typename T, size_t N, typename Op = cpp::plus<>> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, Op op = {}) { + return reduce(v, op); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::plus<>) { + return __builtin_reduce_add(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::multiplies<>) { + return __builtin_reduce_mul(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_and<>) { + return __builtin_reduce_and(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_or<>) { + return __builtin_reduce_or(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_xor<>) { + return __builtin_reduce_xor(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T hmin(simd<T, N> v) { + return __builtin_reduce_min(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T hmax(simd<T, N> v) { + return __builtin_reduce_max(v); +} + +// Accessor helpers. +template <typename T> +LIBC_INLINE enable_if_simd_t<T> load_unaligned(const void *ptr) { + T tmp; + __builtin_memcpy(&tmp, ptr, sizeof(T)); + return tmp; +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> load_aligned(const void *ptr) { + return load_unaligned<T>(__builtin_assume_aligned(ptr, alignof(T))); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> store_unaligned(T v, void *ptr) { + __builtin_memcpy(ptr, &v, sizeof(T)); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> store_aligned(T v, void *ptr) { + store_unaligned<T>(v, __builtin_assume_aligned(ptr, alignof(T))); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> +masked_load(simd<bool, simd_size_v<T>> m, void *ptr, + T passthru = internal::poison<simd_element_type<T>>()) { + return __builtin_masked_load(m, ptr, passthru); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> masked_store(simd<bool, simd_size_v<T>> m, T v, + void *ptr) { + __builtin_masked_store( + m, v, static_cast<T *>(__builtin_assume_aligned(ptr, alignof(T)))); +} + +// Construction helpers. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> splat(T v) { + return simd<T, N>(v); +} +template <typename T> LIBC_INLINE constexpr static simd<T> splat(T v) { + return splat<T, simd_size_v<simd<T>>>(v); +} +template <typename T, unsigned N> +LIBC_INLINE constexpr static simd<T, N> iota(T base = T(0), T step = T(1)) { + simd<T, N> v{}; + for (unsigned i = 0; i < N; ++i) + v[i] = base + T(i) * step; + return v; +} +template <typename T> +LIBC_INLINE constexpr static simd<T> iota(T base = T(0), T step = T(1)) { + return iota<T, simd_size_v<simd<T>>>(base, step); +} + +// Conditional helpers. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> select(simd<bool, N> m, simd<T, N> x, + simd<T, N> y) { + return m ? x : y; +} + +// TODO: where expressions, scalar overloads, ABI types. + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_HAS_VECTOR_TYPE +#endif diff --git a/libc/src/__support/CPP/tuple.h b/libc/src/__support/CPP/tuple.h new file mode 100644 index 000000000000..cce8e0ef2bfa --- /dev/null +++ b/libc/src/__support/CPP/tuple.h @@ -0,0 +1,144 @@ +//===-- tuple utility -------------------------------------------*- C++ -*-===// +// +// 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 LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H + +#include "src/__support/CPP/type_traits/decay.h" +#include "src/__support/CPP/utility/integer_sequence.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <typename... Ts> struct tuple; +template <> struct tuple<> {}; + +template <typename Head, typename... Tail> +struct tuple<Head, Tail...> : tuple<Tail...> { + Head head; + + LIBC_INLINE constexpr tuple() = default; + + template <typename OHead, typename... OTail> + LIBC_INLINE constexpr tuple &operator=(const tuple<OHead, OTail...> &other) { + head = other.get_head(); + this->get_tail() = other.get_tail(); + return *this; + } + + LIBC_INLINE constexpr tuple(const Head &h, const Tail &...t) + : tuple<Tail...>(t...), head(h) {} + + LIBC_INLINE constexpr Head &get_head() { return head; } + LIBC_INLINE constexpr const Head &get_head() const { return head; } + + LIBC_INLINE constexpr tuple<Tail...> &get_tail() { return *this; } + LIBC_INLINE constexpr const tuple<Tail...> &get_tail() const { return *this; } +}; + +template <typename... Ts> LIBC_INLINE constexpr auto make_tuple(Ts &&...args) { + return tuple<cpp::decay_t<Ts>...>(static_cast<Ts &&>(args)...); +} +template <typename... Ts> LIBC_INLINE constexpr auto tie(Ts &...args) { + return tuple<Ts &...>(args...); +} + +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr auto &get(tuple<Head, Tail...> &t) { + if constexpr (I == 0) + return t.get_head(); + else + return get<I - 1>(t.get_tail()); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr const auto &get(const tuple<Head, Tail...> &t) { + if constexpr (I == 0) + return t.get_head(); + else + return get<I - 1>(t.get_tail()); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr auto &&get(tuple<Head, Tail...> &&t) { + if constexpr (I == 0) + return static_cast<Head &&>(t.get_head()); + else + return get<I - 1>(static_cast<tuple<Tail...> &&>(t.get_tail())); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr const auto &&get(const tuple<Head, Tail...> &&t) { + if constexpr (I == 0) + return static_cast<const Head &&>(t.get_head()); + else + return get<I - 1>(static_cast<const tuple<Tail...> &&>(t.get_tail())); +} + +template <typename T> struct tuple_size; +template <typename... Ts> struct tuple_size<tuple<Ts...>> { + static constexpr size_t value = sizeof...(Ts); +}; + +template <size_t I, typename T> struct tuple_element; +template <size_t I, typename Head, typename... Tail> +struct tuple_element<I, tuple<Head, Tail...>> + : tuple_element<I - 1, tuple<Tail...>> {}; +template <typename Head, typename... Tail> +struct tuple_element<0, tuple<Head, Tail...>> { + using type = cpp::remove_cv_t<cpp::remove_reference_t<Head>>; +}; + +namespace internal { +template <typename... As, typename... Bs, size_t... I, size_t... J> +LIBC_INLINE constexpr auto +tuple_cat(const tuple<As...> &a, const tuple<Bs...> &b, + cpp::index_sequence<I...>, cpp::index_sequence<J...>) { + return tuple<As..., Bs...>(get<I>(a)..., get<J>(b)...); +} + +template <typename First, typename Second, typename... Rest> +LIBC_INLINE constexpr auto tuple_cat(const First &f, const Second &s, + const Rest &...rest) { + auto concat = + tuple_cat(f, s, cpp::make_index_sequence<tuple_size<First>::value>{}, + cpp::make_index_sequence<tuple_size<Second>::value>{}); + if constexpr (sizeof...(Rest)) + return tuple_cat(concat, rest...); + else + return concat; +} +} // namespace internal + +template <typename... Tuples> +LIBC_INLINE constexpr auto tuple_cat(const Tuples &...tuples) { + static_assert(sizeof...(Tuples) > 0, "need at least one element"); + if constexpr (sizeof...(Tuples) == 1) + return (tuples, ...); + else + return internal::tuple_cat(tuples...); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +// Standard namespace definitions required for structured binding support. +namespace std { + +template <class T> struct tuple_size; +template <size_t I, class T> struct tuple_element; + +template <typename... Ts> +struct tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> + : LIBC_NAMESPACE::cpp::tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> {}; + +template <size_t I, typename... Ts> +struct tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> + : LIBC_NAMESPACE::cpp::tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> { +}; + +} // namespace std + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H diff --git a/libc/src/__support/CPP/type_traits/is_complex.h b/libc/src/__support/CPP/type_traits/is_complex.h index 23f05c08ccab..5da1a40892c2 100644 --- a/libc/src/__support/CPP/type_traits/is_complex.h +++ b/libc/src/__support/CPP/type_traits/is_complex.h @@ -13,12 +13,17 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" // LIBC_TYPES_HAS_CFLOAT16 && LIBC_TYPES_HAS_CFLOAT128 +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/complex_types.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { // is_complex +#ifdef LIBC_COMPILER_IS_MSVC +// TODO: Add support for complex types with MSVC. +template <typename T> struct is_complex : false_type {}; +#else template <typename T> struct is_complex { private: template <typename Head, typename... Args> @@ -40,6 +45,8 @@ public: #endif >(); }; +#endif // LIBC_COMPILER_IS_MSVC + template <typename T> LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex<T>::value; template <typename T1, typename T2> diff --git a/libc/src/__support/CPP/utility/integer_sequence.h b/libc/src/__support/CPP/utility/integer_sequence.h index 06643d505aca..17c3dbfd229c 100644 --- a/libc/src/__support/CPP/utility/integer_sequence.h +++ b/libc/src/__support/CPP/utility/integer_sequence.h @@ -5,12 +5,15 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/macros/config.h" +#include <stddef.h> + namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -34,6 +37,13 @@ template <typename T, int N> using make_integer_sequence = typename detail::make_integer_sequence<T, N - 1>::type; +// index sequence +template <size_t... Ints> +using index_sequence = integer_sequence<size_t, Ints...>; +template <int N> +using make_index_sequence = + typename detail::make_integer_sequence<size_t, N - 1>::type; + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL |
