5#include "native/value_traits.h"
15 enum class family { leaf, std_array, legacy };
16 template<
class T>
struct shape {
static constexpr auto kind=family::leaf; };
17 template<
class T,std::
size_t N>
struct array_shape {
18 static constexpr std::size_t size=N;
19 template<std::
size_t>
using element_type=T;
21 template<
class T,std::
size_t N>
struct shape<std::array<T,N>> : array_shape<T,N> {
22 static constexpr auto kind=family::std_array;
24 template<
class T>
using shape_t=shape<std::remove_cvref_t<T>>;
25 template<
class T>
inline constexpr bool is_array=
26 shape_t<T>::kind==family::std_array || shape_t<T>::kind==family::legacy;
30 template<
class T>
concept pack=detail::shape_t<T>::kind==detail::family::std_array;
33 template<std::
size_t I,
class P>
34 native_inline constexpr decltype(
auto) source_get(P&& value)
noexcept {
35 if constexpr (shape_t<P>::kind==family::legacy)
36 return std::get<I>(std::forward<P>(value).registers);
37 else return std::get<I>(std::forward<P>(value));
42 template<
class T>
struct element_traits {};
44 template<
class T,std::
size_t N,::native::isa<> A>
46 template<std::
size_t N,::native::isa<> A>
48 template<
class T>
using adapted_t=
typename element_traits<std::remove_cvref_t<T>>::type;
49 template<
class T>
concept adaptable=
requires {
typename adapted_t<T>; };
50 template<
class P>
requires is_array<P> && adaptable<typename shape_t<P>::template element_type<0>>
51 struct element_traits<P> {
52 using type=std::array<adapted_t<typename shape_t<P>::template element_type<0>>,shape_t<P>::size>;
54 template<
class T>
struct promotion_traits {};
55 template<adaptable T>
struct promotion_traits<T> {
56 using canonical_type=std::conditional_t<shape_t<T>::kind==family::leaf,
57 std::array<adapted_t<T>,1>,adapted_t<T>>;
60 template<adaptable T>
native_inline constexpr adapted_t<T> adapt_element(T&& value);
61 template<
class P,std::size_t... I>
62 native_inline constexpr adapted_t<P> adapt_pack(P&& value,std::index_sequence<I...>) {
63 return {{adapt_element(source_get<I>(std::forward<P>(value)))...}};
66 native_inline constexpr adapted_t<T> adapt_element(T&& value) {
67 if constexpr (shape_t<T>::kind==family::leaf)
68 return adapted_t<T>(std::forward<T>(value));
69 else return adapt_pack(std::forward<T>(value),std::make_index_sequence<shape_t<T>::size>{});
73 template<
class T>
struct traits : detail::promotion_traits<std::remove_cvref_t<T>> {};
74 template<
class T>
using canonical_t=
typename traits<std::remove_cvref_t<T>>::canonical_type;
75 template<
class T>
concept promotable=
requires {
typename canonical_t<T>; };
78 template<promotable T>
80 if constexpr (detail::shape_t<T>::kind==detail::family::leaf)
81 return {{detail::adapt_element(std::forward<T>(value))}};
82 else return detail::adapt_element(std::forward<T>(value));
86 template<
class T>
inline constexpr bool scalar_vector=
false;
87 template<
class T>
inline constexpr bool scalar_vector<::native::simd<T,1,::native::scalar>> =
true;
88 template<
class T>
inline constexpr bool scalar_mask=
false;
89 template<
class T>
requires (std::same_as<T,bool> || ::native::detail::is_mask_lane<T>)
90 inline constexpr bool scalar_mask<::native::simd<T,1,::native::scalar>> =
true;
91 template<>
inline constexpr bool scalar_mask<::native::predicate<1,::native::scalar>> =
true;
93 template<
class Original,
class P>
consteval bool compatible_pack() {
94 if constexpr (!pack<P>)
return false;
95 else if constexpr (shape_t<Original>::kind==family::leaf)
return shape_t<P>::size==1;
96 else if constexpr (shape_t<Original>::size!=shape_t<P>::size)
return false;
98 using E=
typename shape_t<Original>::template element_type<0>;
99 using R=
typename shape_t<P>::template element_type<0>;
100 if constexpr (shape_t<E>::kind==family::leaf)
return true;
101 else return compatible_pack<E,R>();
105 template<
class Original,
class R>
native_inline constexpr auto restore_element(R&& value);
106 template<
class Original,
class P,std::size_t... I>
107 native_inline constexpr auto restore_pack(P&& value,std::index_sequence<I...>) {
108 using S=shape_t<Original>;
109 using E=
typename S::template element_type<0>;
110 using V=
typename shape_t<P>::template element_type<0>;
111 using R=
decltype(restore_element<E>(std::declval<V>()));
112 if constexpr (S::kind==family::std_array)
113 return std::array<R,S::size>{{restore_element<E>(std::get<I>(std::forward<P>(value)))...}};
114 else if constexpr (
requires(std::array<R,S::size> a) { S::restore(a); })
115 return S::restore(std::array<R,S::size>{{restore_element<E>(std::get<I>(std::forward<P>(value)))...}});
116 else return typename S::template rebind<R>{std::array<R,S::size>{{
117 restore_element<E>(std::get<I>(std::forward<P>(value)))...}}};
119 template<
class Original,
class R>
121 if constexpr (shape_t<Original>::kind!=family::leaf)
122 return restore_pack<Original>(std::forward<R>(value),
123 std::make_index_sequence<shape_t<Original>::size>{});
124 else if constexpr (std::same_as<std::remove_cvref_t<Original>,
float> &&
125 scalar_mask<std::remove_cvref_t<R>>)
126 return value.to_native()!=0;
127 else if constexpr (std::same_as<std::remove_cvref_t<Original>,
float> &&
128 scalar_vector<std::remove_cvref_t<R>>)
129 return value.to_native();
130 else return std::remove_cvref_t<R>(std::forward<R>(value));
135 template<
class Original,pack P>
requires promotable<Original> &&
136 (detail::compatible_pack<Original,P>())
138 if constexpr (detail::shape_t<Original>::kind==detail::family::leaf)
139 return detail::restore_element<Original>(std::get<0>(std::forward<P>(result)));
140 else return detail::restore_pack<Original>(std::forward<P>(result),
141 std::make_index_sequence<detail::shape_t<Original>::size>{});
145 template<
class From,
class T>
using copy_const_t=
146 std::conditional_t<std::is_const_v<std::remove_reference_t<From>>,std::add_const_t<T>,T>;
147 template<
class From,
class T>
using copy_cv_t=
148 std::conditional_t<std::is_volatile_v<std::remove_reference_t<From>>,
149 std::add_volatile_t<copy_const_t<From,T>>,copy_const_t<From,T>>;
150 template<
class P>
using element_argument_t=
151 std::conditional_t<std::is_lvalue_reference_v<P>,
152 copy_cv_t<P,typename shape_t<P>::template element_type<0>>&,
153 copy_cv_t<P,typename shape_t<P>::template element_type<0>>&&>;
154 template<
class F,
class... P>
using mapped_t=
155 std::remove_cvref_t<std::invoke_result_t<F&,element_argument_t<P>...>>;
156 template<std::size_t I,
class F,
class... P>
157 native_inline constexpr decltype(
auto) map_element(F& function,P&&... value) {
158 return std::invoke(function,std::get<I>(std::forward<P>(value))...);
160 template<
class F,
class P,
class... Rest,std::size_t... I>
161 consteval bool map_compatible(std::index_sequence<I...>) {
162 if constexpr (!std::is_invocable_v<F&,element_argument_t<P>,element_argument_t<Rest>...>)
return false;
164 using R=mapped_t<F,P,Rest...>;
165 if constexpr (!std::is_object_v<R>)
return false;
166 else return requires(F& function,P&& first,Rest&&... rest) {
167 std::array<R,
sizeof...(I)>{{map_element<I>(function,
168 std::forward<P>(first),std::forward<Rest>(rest)...)...}};
172 template<
class F,
class P,
class... Rest,std::size_t... I>
173 native_inline constexpr auto map_pack(F&& function,std::index_sequence<I...>,P&& first,Rest&&... rest) {
174 return std::array<mapped_t<F,P,Rest...>,
sizeof...(I)>{{
175 map_element<I>(function,std::forward<P>(first),std::forward<Rest>(rest)...)...}};
180 template<
class F,
pack P,
pack... Rest>
181 requires ((detail::shape_t<P>::size==detail::shape_t<Rest>::size) && ...) &&
182 (detail::map_compatible<F,P,Rest...>(std::make_index_sequence<detail::shape_t<P>::size>{}))
183 native_inline constexpr auto map(F&& function,P&& first,Rest&&... rest) {
184 return detail::map_pack(std::forward<F>(function),
185 std::make_index_sequence<detail::shape_t<P>::size>{},
186 std::forward<P>(first),std::forward<Rest>(rest)...);
Compiler attributes for host code, with shader-safe shared modifiers.
A homogeneous batch stored in a standard array.
#define native_inline
inline [[always_inline]]
Omitted architecture arguments use the native.simd provider's baseline.