33 * Martin Renou *
44 * Copyright (c) QuantStack *
55 * Copyright (c) Serge Guelton *
6- * Copyright (c) Marco Barbone *
76 * *
87 * Distributed under the terms of the BSD 3-Clause License. *
98 * *
@@ -27,143 +26,170 @@ namespace xsimd
2726 }
2827 }
2928
29+ /* Existing patterns kept for backward compatibility */
30+
3031 template <class T >
3132 struct Reversor
3233 {
3334 static constexpr T get (T i, T n) { return n - 1 - i; }
3435 };
36+
3537 template <class T >
3638 struct Last
3739 {
3840 static constexpr T get (T, T n) { return n - 1 ; }
3941 };
42+
4043 template <class T >
41- struct DupReal
44+ struct DupReal /* 0,0,2,2,… */
4245 {
4346 static constexpr T get (T i, T) { return (i & ~T { 1 }); }
4447 };
4548
49+ /* New patterns requested */
50+
4651 template <class T >
47- struct DupImag
52+ struct DupImag /* 1,1,3,3,… */
4853 {
4954 static constexpr T get (T i, T) { return (i & ~T { 1 }) + 1 ; }
5055 };
56+
5157 template <class T >
52- struct SwapRI
58+ struct SwapRI /* 1,0,3,2,… swap real <-> imag per complex number */
5359 {
5460 static constexpr T get (T i, T)
5561 {
5662 return i ^ T { 1 };
5763 }
5864 };
65+
5966 template <class T >
60- struct Identity
67+ struct Identity /* 0,1,2,3,… */
6168 {
6269 static constexpr T get (T i, T) { return i; }
6370 };
71+
6472 template <class T >
65- struct DupLowPair
73+ struct DupLowPair /* 0,0,1,1,… */
6674 {
6775 static constexpr T get (T i, T) { return i / 2 ; }
6876 };
77+
6978 template <class T >
70- struct DupHighPair
79+ struct DupHighPair /* n/2,n/2,n/2+1,n/2+1,… */
7180 {
7281 static constexpr T get (T i, T n) { return n / 2 + i / 2 ; }
7382 };
7483
7584 template <class T >
76- struct RotateRight1
77- {
78- static constexpr T get (T i, T n) { return (i + n - 1 ) % n; }
79- };
80- template <class T >
81- struct RotateLeft1
85+ struct as_index
8286 {
83- static constexpr T get (T i, T n) { return (i + 1 ) % n; }
87+ using type = xsimd:: as_unsigned_integer_t <T>;
8488 };
8589
8690 template <class T >
87- struct ReversePairs
91+ struct as_index <std:: complex <T>> : as_index<T>
8892 {
89- static constexpr T get (T i, T) { return (i & ~T { 1 }) | (1 - (i & T { 1 })); }
9093 };
91- template <class T >
92- struct EvenThenOdd
94+
95+ template <typename T, std::size_t N>
96+ struct init_swizzle_base
9397 {
94- static constexpr T get (T i, T n)
98+ using swizzle_vector_type = std::array<T, N>;
99+
100+ swizzle_vector_type lhs_in {},
101+ exped_reverse {}, exped_fill {}, exped_dup {},
102+ exped_ror {}, exped_rol {}, exped_rol2 {},
103+ /* new patterns */
104+ exped_dup_imag {}, exped_swap_ri {}, exped_identity {},
105+ exped_dup_low {}, exped_dup_high {}, exped_generic {};
106+
107+ template <int ... Indices>
108+ std::vector<swizzle_vector_type> create_swizzle_vectors ()
95109 {
96- return (i < n / 2 ? 2 * i : 2 * (i - n / 2 ) + 1 );
110+ std::vector<swizzle_vector_type> vects;
111+
112+ /* 0) Generate input data */
113+ for (std::size_t i = 0 ; i < N; ++i)
114+ {
115+ lhs_in[i] = static_cast <T>(2 * i + 1 );
116+ }
117+ vects.push_back (lhs_in);
118+
119+ /* 1‑3) Original expectations */
120+ for (std::size_t i = 0 ; i < N; ++i)
121+ {
122+ exped_reverse[i] = lhs_in[N - 1 - i];
123+ exped_fill[i] = lhs_in[N - 1 ];
124+ exped_dup[i] = lhs_in[(i & ~std::size_t { 1 })];
125+ exped_ror[i] = lhs_in[(i + N - 1 ) % N];
126+ exped_rol[i] = lhs_in[(i + 1 ) % N];
127+ exped_rol2[i] = lhs_in[(i + N - 1 ) % N]; // rotate_left<N-1>
128+ }
129+
130+ /* New expectations built through generic helper */
131+ fill_pattern<DupImag>(exped_dup_imag, lhs_in);
132+ fill_pattern<SwapRI>(exped_swap_ri, lhs_in);
133+ fill_pattern<Identity>(exped_identity, lhs_in);
134+ fill_pattern<DupLowPair>(exped_dup_low, lhs_in);
135+ fill_pattern<DupHighPair>(exped_dup_high, lhs_in);
136+
137+ /* Push in the original order, then the new ones */
138+ vects.push_back (exped_reverse); // 1
139+ vects.push_back (exped_fill); // 2
140+ vects.push_back (exped_dup); // 3
141+ vects.push_back (exped_ror); // 4
142+ vects.push_back (exped_rol); // 5
143+ vects.push_back (exped_rol2); // 6
144+
145+ vects.push_back (exped_dup_imag); // 7
146+ vects.push_back (exped_swap_ri); // 8
147+ vects.push_back (exped_identity); // 9
148+ vects.push_back (exped_dup_low); // 10
149+ vects.push_back (exped_dup_high); // 11
150+ vects.push_back (exped_generic); // 12
151+
152+ return vects;
97153 }
98154 };
99- template <class T >
100- struct OddThenEven
155+ template <class B >
156+ struct insert_test
101157 {
102- static constexpr T get (T i, T n)
158+ using batch_type = B;
159+ using value_type = typename B::value_type;
160+ static constexpr std::size_t size = B::size;
161+
162+ void insert_first ()
103163 {
104- return (i < n / 2 ? 2 * i + 1 : 2 * (i - n / 2 ));
164+ value_type fill_value = 0 ;
165+ value_type sentinel_value = 1 ;
166+ batch_type v (fill_value);
167+ batch_type w = insert (v, sentinel_value, ::xsimd::index<0 >());
168+ std::array<value_type, batch_type::size> data {};
169+ w.store_unaligned (data.data ());
170+ CHECK_SCALAR_EQ (data.front (), sentinel_value);
171+ for (std::size_t i = 1 ; i < batch_type::size; ++i)
172+ CHECK_SCALAR_EQ (data[i], fill_value);
105173 }
106- };
107- template <class T >
108- struct InterleavePairs
109- {
110- static constexpr T get (T i, T n)
174+
175+ void insert_last ()
111176 {
112- return (i & 1 ) ? (i / 2 + n / 2 ) : (i / 2 );
177+ value_type fill_value = 0 ;
178+ value_type sentinel_value = 1 ;
179+ batch_type v (fill_value);
180+ batch_type w = insert (v, sentinel_value, ::xsimd::index<batch_type::size - 1 >());
181+ std::array<value_type, batch_type::size> data {};
182+ w.store_unaligned (data.data ());
183+ for (std::size_t i = 0 ; i < batch_type::size - 1 ; ++i)
184+ CHECK_SCALAR_EQ (data[i], fill_value);
185+ CHECK_SCALAR_EQ (data.back (), sentinel_value);
113186 }
114187 };
115- template <class T >
116- struct as_index
117- {
118- using type = xsimd::as_unsigned_integer_t <T>;
119- };
120-
121- template <class T >
122- struct as_index <std::complex <T>> : as_index<T>
123- {
124- };
125188} // namespace xsimd
126189
127- // ------------------------------------------------------------------------------
128- // insert_test: unchanged from original
129- // ------------------------------------------------------------------------------
130- template <class B >
131- struct insert_test
132- {
133- using batch_type = B;
134- using value_type = typename B::value_type;
135-
136- void insert_first ()
137- {
138- value_type fill_value = 0 ;
139- value_type sentinel_value = 1 ;
140- batch_type v (fill_value);
141- batch_type w = xsimd::insert (v, sentinel_value, xsimd::index<0 >());
142- std::array<value_type, batch_type::size> data {};
143- w.store_unaligned (data.data ());
144- CHECK_SCALAR_EQ (data.front (), sentinel_value);
145- for (std::size_t i = 1 ; i < batch_type::size; ++i)
146- CHECK_SCALAR_EQ (data[i], fill_value);
147- }
148-
149- void insert_last ()
150- {
151- value_type fill_value = 0 ;
152- value_type sentinel_value = 1 ;
153- batch_type v (fill_value);
154- batch_type w = xsimd::insert (v, sentinel_value,
155- xsimd::index<batch_type::size - 1 >());
156- std::array<value_type, batch_type::size> data {};
157- w.store_unaligned (data.data ());
158- for (std::size_t i = 0 ; i < batch_type::size - 1 ; ++i)
159- CHECK_SCALAR_EQ (data[i], fill_value);
160- CHECK_SCALAR_EQ (data.back (), sentinel_value);
161- }
162- };
163-
164190TEST_CASE_TEMPLATE (" [insert_test]" , B, BATCH_TYPES)
165191{
166- insert_test<B> Test;
192+ xsimd:: insert_test<B> Test;
167193 SUBCASE (" insert_first" ) { Test.insert_first (); }
168194 SUBCASE (" insert_last" ) { Test.insert_last (); }
169195}
@@ -174,87 +200,83 @@ struct swizzle_test
174200 using batch_type = B;
175201 using value_type = typename B::value_type;
176202 using arch_type = typename B::arch_type;
177- static constexpr std::size_t N = B::size;
178- using vec_t = std::array<value_type, N>;
179-
180- // Build the input [1,3,5,...,2N-1]
181- static vec_t make_lhs ()
182- {
183- vec_t v;
184- for (std::size_t i = 0 ; i < N; ++i)
185- v[i] = static_cast <value_type>(2 * i + 1 );
186- return v;
187- }
203+ static constexpr std::size_t size = B::size;
188204
189- template <template <class > class Pattern >
190- void run ()
205+ template <template <class > class Pattern , std:: size_t VectIndex >
206+ void check_swizzle_pattern ()
191207 {
192- vec_t lhs = make_lhs ();
193- vec_t expect = lhs;
194- xsimd::fill_pattern<Pattern>(expect, lhs);
208+ xsimd::init_swizzle_base<value_type, size> swb;
209+ auto vecs = swb.create_swizzle_vectors ();
210+ auto v_lhs = vecs[0 ];
211+ auto v_exped = vecs[VectIndex];
195212
196- auto b_lhs = batch_type::load_unaligned (lhs .data ());
197- auto b_expect = batch_type::load_unaligned (expect .data ());
213+ batch_type b_lhs = batch_type::load_unaligned (v_lhs .data ());
214+ batch_type b_exped = batch_type::load_unaligned (v_exped .data ());
198215
199216 using idx_t = typename xsimd::as_index<value_type>::type;
200217 auto idx_batch = xsimd::make_batch_constant<idx_t , Pattern<idx_t >, arch_type>();
201218
202- CHECK_BATCH_EQ (xsimd::swizzle (b_lhs, idx_batch), b_expect);
203- CHECK_BATCH_EQ (xsimd::swizzle (b_lhs,
204- static_cast <xsimd::batch<idx_t , arch_type>>(idx_batch)),
205- b_expect);
219+ CHECK_BATCH_EQ (xsimd::swizzle (b_lhs, idx_batch), b_exped);
220+ CHECK_BATCH_EQ (xsimd::swizzle (b_lhs, static_cast <xsimd::batch<idx_t , arch_type>>(idx_batch)), b_exped);
206221 }
207222
208223 void rotate_right ()
209224 {
210- vec_t lhs = make_lhs (), expect;
211- std::rotate_copy (lhs.begin (), lhs.end () - 1 , lhs.end (), expect.begin ());
212- CHECK_BATCH_EQ (xsimd::rotate_right<1 >(batch_type::load_unaligned (lhs.data ())),
213- batch_type::load_unaligned (expect.data ()));
225+ xsimd::init_swizzle_base<value_type, size> sb;
226+ auto vv = sb.create_swizzle_vectors ();
227+ batch_type b_lhs = batch_type::load_unaligned (vv[0 ].data ());
228+ batch_type b_exped = batch_type::load_unaligned (vv[4 ].data ());
229+ CHECK_BATCH_EQ (xsimd::rotate_right<1 >(b_lhs), b_exped);
214230 }
231+
215232 void rotate_left ()
216233 {
217- vec_t lhs = make_lhs (), expect;
218- std::rotate_copy (lhs.begin (), lhs.begin () + 1 , lhs.end (), expect.begin ());
219- CHECK_BATCH_EQ (xsimd::rotate_left<1 >(batch_type::load_unaligned (lhs.data ())),
220- batch_type::load_unaligned (expect.data ()));
234+ xsimd::init_swizzle_base<value_type, size> sb;
235+ auto vv = sb.create_swizzle_vectors ();
236+ batch_type b_lhs = batch_type::load_unaligned (vv[0 ].data ());
237+ batch_type b_exped = batch_type::load_unaligned (vv[5 ].data ());
238+ CHECK_BATCH_EQ (xsimd::rotate_left<1 >(b_lhs), b_exped);
221239 }
240+
222241 void rotate_left_inv ()
223242 {
224- vec_t lhs = make_lhs (), expect;
225- std::rotate_copy (lhs.begin (), lhs.end () - 1 , lhs.end (), expect.begin ());
226- CHECK_BATCH_EQ (xsimd::rotate_left<N - 1 >(batch_type::load_unaligned (lhs.data ())),
227- batch_type::load_unaligned (expect.data ()));
243+ xsimd::init_swizzle_base<value_type, size> sb;
244+ auto vv = sb.create_swizzle_vectors ();
245+ batch_type b_lhs = batch_type::load_unaligned (vv[0 ].data ());
246+ batch_type b_exped = batch_type::load_unaligned (vv[6 ].data ());
247+ CHECK_BATCH_EQ (xsimd::rotate_left<size - 1 >(b_lhs), b_exped);
228248 }
229- };
230249
231- // Macro to instantiate one SUBCASE per pattern
232- #define XSIMD_SWIZZLE_PATTERN_CASE (PAT ) \
233- SUBCASE (#PAT) { swizzle_test<B>().template run <xsimd::PAT>(); }
250+ void swizzle_reverse () { check_swizzle_pattern<xsimd::Reversor, 1 >(); }
251+ void swizzle_fill () { check_swizzle_pattern<xsimd::Last, 2 >(); }
252+ void swizzle_dup () { check_swizzle_pattern<xsimd::DupReal, 3 >(); }
253+ void dup_imag () { check_swizzle_pattern<xsimd::DupImag, 7 >(); }
254+ void swap_ri () { check_swizzle_pattern<xsimd::SwapRI, 8 >(); }
255+ void identity () { check_swizzle_pattern<xsimd::Identity, 9 >(); }
256+ void dup_low_pair () { check_swizzle_pattern<xsimd::DupLowPair, 10 >(); }
257+ void dup_high_pair () { check_swizzle_pattern<xsimd::DupHighPair, 11 >(); }
258+ };
234259
235260TEST_CASE_TEMPLATE (" [swizzle]" , B, BATCH_SWIZZLE_TYPES)
236261{
237- // All existing patterns:
238- XSIMD_SWIZZLE_PATTERN_CASE (Reversor);
239- XSIMD_SWIZZLE_PATTERN_CASE (Last);
240- XSIMD_SWIZZLE_PATTERN_CASE (DupReal);
241- XSIMD_SWIZZLE_PATTERN_CASE (DupImag);
242- XSIMD_SWIZZLE_PATTERN_CASE (SwapRI);
243- XSIMD_SWIZZLE_PATTERN_CASE (Identity);
244- XSIMD_SWIZZLE_PATTERN_CASE (DupLowPair);
245- XSIMD_SWIZZLE_PATTERN_CASE (DupHighPair);
246- XSIMD_SWIZZLE_PATTERN_CASE (RotateRight1);
247- XSIMD_SWIZZLE_PATTERN_CASE (RotateLeft1);
248- XSIMD_SWIZZLE_PATTERN_CASE (ReversePairs);
249- XSIMD_SWIZZLE_PATTERN_CASE (EvenThenOdd);
250- XSIMD_SWIZZLE_PATTERN_CASE (OddThenEven);
251- XSIMD_SWIZZLE_PATTERN_CASE (InterleavePairs);
252- // Rotation checks:
253- SUBCASE (" rotate_left" ) { swizzle_test<B>().rotate_left (); }
254- SUBCASE (" rotate_left_inv" ) { swizzle_test<B>().rotate_left_inv (); }
255- SUBCASE (" rotate_right" ) { swizzle_test<B>().rotate_right (); }
256- }
262+ swizzle_test<B> t;
263+
264+ SUBCASE (" reverse" ) { t.swizzle_reverse (); }
257265
258- #undef XSIMD_SWIZZLE_PATTERN_CASE
266+ SUBCASE (" rotate" )
267+ {
268+ t.rotate_left ();
269+ t.rotate_left_inv ();
270+ t.rotate_right ();
271+ }
272+
273+ SUBCASE (" fill" ) { t.swizzle_fill (); }
274+ SUBCASE (" dup real" ) { t.swizzle_dup (); }
275+ SUBCASE (" dup imag" ) { t.dup_imag (); }
276+ SUBCASE (" swap R/I" ) { t.swap_ri (); }
277+ SUBCASE (" identity" ) { t.identity (); }
278+ SUBCASE (" dup low pair" ) { t.dup_low_pair (); }
279+ SUBCASE (" dup high pair" ) { t.dup_high_pair (); }
280+ }
259281
260282#endif /* XSIMD_NO_SUPPORTED_ARCHITECTURE */
0 commit comments