Skip to content

Commit 5830697

Browse files
committed
Add swizzle operations
1 parent 83bf703 commit 5830697

File tree

8 files changed

+251
-25
lines changed

8 files changed

+251
-25
lines changed

docs/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ API Reference
66
api/unary_operators.rst
77
api/binary_operators.rst
88
api/reductions.rst
9+
api/shuffling.rst
910
api/mathematical.rst

docs/build_api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ def build_index_page(groups):
9494
"resize",
9595
"for_each",
9696
],
97+
"Shuffling": [
98+
"concat",
99+
"swizzle",
100+
"first",
101+
"last",
102+
"reversed",
103+
"rotate_left",
104+
"rotate_right",
105+
],
97106
"Unary Operators": [
98107
"fill",
99108
"fill_like",

docs/license.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
License
2+
=======
3+
4+
.. include:: ../LICENSE
5+

include/kernel_float.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "kernel_float/meta.h"
1212
#include "kernel_float/reduce.h"
1313
#include "kernel_float/storage.h"
14+
#include "kernel_float/swizzle.h"
1415
#include "kernel_float/unops.h"
1516

1617
#endif

include/kernel_float/meta.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ template<size_t... Is>
1818
struct index_sequence {};
1919

2020
namespace detail {
21-
template<size_t N, size_t... Is>
22-
struct make_index_sequence_helper: make_index_sequence_helper<N - 1, N - 1, Is...> {};
21+
template<size_t N, size_t X, size_t... Is>
22+
struct make_index_sequence_helper: make_index_sequence_helper<N - 1, X + N - 1, Is...> {};
2323

24-
template<size_t... Is>
25-
struct make_index_sequence_helper<0, Is...> {
24+
template<size_t... Is, size_t X>
25+
struct make_index_sequence_helper<0, X, Is...> {
2626
using type = index_sequence<Is...>;
2727
};
2828

2929
} // namespace detail
3030

31-
template<size_t N>
32-
using make_index_sequence = typename detail::make_index_sequence_helper<N>::type;
31+
template<size_t N, size_t Offset = 0>
32+
using make_index_sequence = typename detail::make_index_sequence_helper<N, Offset>::type;
3333

3434
namespace detail {
3535
template<typename T>

include/kernel_float/reduce.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct reduce_helper<F, vector_compound<T, N>> {
5959
* =======
6060
* ```
6161
* vec<int, 3> x = {5, 2, 1};
62-
* int y = reduce(x, [](int a, int b) { return a + b; }); // returns 8
62+
* int y = reduce(x, [](int a, int b) { return a + b; }); // returns 5+2+1=8
6363
* ```
6464
*/
6565
template<typename F, typename V>
@@ -76,7 +76,7 @@ KERNEL_FLOAT_INLINE vector_value_type<V> reduce(F fun, V&& input) {
7676
* =======
7777
* ```
7878
* vec<int, 3> x = {5, 0, 2, 1, 0};
79-
* int y = sum(x); // Returns 8
79+
* int y = min(x); // Returns 0
8080
* ```
8181
*/
8282
template<typename V, typename T = vector_value_type<V>>
@@ -91,7 +91,7 @@ KERNEL_FLOAT_INLINE T min(V&& input) {
9191
* =======
9292
* ```
9393
* vec<int, 3> x = {5, 0, 2, 1, 0};
94-
* int y = sum(x); // Returns 8
94+
* int y = max(x); // Returns 5
9595
* ```
9696
*/
9797
template<typename V, typename T = vector_value_type<V>>
@@ -121,7 +121,7 @@ KERNEL_FLOAT_INLINE T sum(V&& input) {
121121
* =======
122122
* ```
123123
* vec<int, 5> x = {5, 0, 2, 1, 0};
124-
* int y = sum(x); // Returns 5+0+2+1+0 = 8
124+
* int y = sum(x); // Returns 5*0*2*1*0 = 0
125125
* ```
126126
*/
127127
template<typename V, typename T = vector_value_type<V>>
@@ -131,7 +131,7 @@ KERNEL_FLOAT_INLINE T product(V&& input) {
131131

132132
/**
133133
* Check if all elements in the given vector ``input`` are non-zero. An element ``v`` is considered
134-
* non-zero if ``bool(v)`` returns ``true``.
134+
* non-zero if ``bool(v)==true``.
135135
*/
136136
template<typename V>
137137
KERNEL_FLOAT_INLINE bool all(V&& input) {
@@ -140,7 +140,7 @@ KERNEL_FLOAT_INLINE bool all(V&& input) {
140140

141141
/**
142142
* Check if any element in the given vector ``input`` is non-zero. An element ``v`` is considered
143-
* non-zero if ``bool(v)`` returns ``true``.
143+
* non-zero if ``bool(v)==true``.
144144
*/
145145
template<typename V>
146146
KERNEL_FLOAT_INLINE bool any(V&& input) {
@@ -149,13 +149,13 @@ KERNEL_FLOAT_INLINE bool any(V&& input) {
149149

150150
/**
151151
* Count the number of non-zero items in the given vector ``input``. An element ``v`` is considered
152-
* non-zero if ``bool(v)`` returns true.
152+
* non-zero if ``bool(v)==true``.
153153
*
154154
* Example
155155
* =======
156156
* ```
157-
* vec<int, 3> x = {5, 0, 2, 1, 0};
158-
* int y = count(x); // Returns 3
157+
* vec<int, 5> x = {5, 0, 2, 1, 0};
158+
* int y = count(x); // Returns 3 (5, 2, 1 are non-zero)
159159
* ```
160160
*/
161161
template<typename V>

include/kernel_float/storage.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,6 @@ struct vector_accessor {
7979
}
8080
};
8181

82-
template<typename Output, typename Input, typename Indices, typename = void>
83-
struct vector_swizzle;
84-
85-
template<typename Output, typename Input, size_t... Is>
86-
struct vector_swizzle<Output, Input, index_sequence<Is...>> {
87-
KERNEL_FLOAT_INLINE static Output call(const Input& storage) {
88-
return Output {storage.get(const_index<Is> {})...};
89-
}
90-
};
91-
9282
template<typename T>
9383
struct vector_empty {
9484
KERNEL_FLOAT_INLINE vector_empty(T value = {}) {}

include/kernel_float/swizzle.h

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#ifndef KERNEL_FLOAT_SWIZZLE_H
2+
#define KERNEL_FLOAT_SWIZZLE_H
3+
4+
#include "storage.h"
5+
6+
namespace kernel_float {
7+
8+
template<typename Output, typename Input, typename Indices, typename = void>
9+
struct vector_swizzle;
10+
11+
template<typename Output, typename Input, size_t... Is>
12+
struct vector_swizzle<Output, Input, index_sequence<Is...>> {
13+
KERNEL_FLOAT_INLINE static Output call(const Input& storage) {
14+
return Output {storage.get(const_index<Is> {})...};
15+
}
16+
};
17+
18+
/**
19+
* "Swizzles" the vector. Returns a new vector where the elements are provided by the given indices.
20+
*
21+
* # Example
22+
* ```
23+
* vec<int, 6> x = {0, 1, 2, 3, 4, 5, 6};
24+
* vec<int, 3> a = swizzle<0, 1, 2>(x); // 0, 1, 2
25+
* vec<int, 3> b = swizzle<2, 1, 0>(x); // 2, 1, 0
26+
* vec<int, 3> c = swizzle<1, 1, 1>(x); // 1, 1, 1
27+
* vec<int, 4> d = swizzle<0, 2, 4, 6>(x); // 0, 2, 4, 6
28+
* ```
29+
*/
30+
template<size_t... Is, typename V>
31+
KERNEL_FLOAT_INLINE vector_storage<vector_value_type<V>, sizeof...(Is)>
32+
swizzle(V&& input, index_sequence < Is... >= {}) {
33+
using Input = into_vector_type<V>;
34+
using Output = vector_storage<vector_value_type<V>, sizeof...(Is)>;
35+
36+
return vector_swizzle<Output, Input, index_sequence<Is...>>::call(
37+
into_vector(std::forward<V>(input)));
38+
}
39+
40+
/**
41+
* Takes the first ``N`` elements from the given vector and returns a new vector of length ``N``.
42+
*
43+
* # Example
44+
* ```
45+
* vec<int, 6> x = {1, 2, 3, 4, 5, 6};
46+
* vec<int, 6> y = first<3>(x); // 1, 2, 3
47+
* int z = first(x); // 1
48+
* ```
49+
*/
50+
template<size_t N = 1, typename V>
51+
KERNEL_FLOAT_INLINE vector_storage<vector_value_type<V>, N> first(V&& input) {
52+
static_assert(N <= vector_size<V>, "N cannot exceed vector size");
53+
using Indices = make_index_sequence<N>;
54+
return swizzle(std::forward<V>(input), Indices {});
55+
}
56+
57+
/**
58+
* Takes the last ``N`` elements from the given vector and returns a new vector of length ``N``.
59+
*
60+
* # Example
61+
* ```
62+
* vec<int, 6> x = {1, 2, 3, 4, 5, 6};
63+
* vec<int, 6> y = last<3>(x); // 4, 5, 6
64+
* int z = last(x); // 6
65+
* ```
66+
*/
67+
template<size_t N = 1, typename V>
68+
KERNEL_FLOAT_INLINE vector_storage<vector_value_type<V>, N> last(V&& input) {
69+
static_assert(N <= vector_size<V>, "N cannot exceed vector size");
70+
using Indices = make_index_sequence<N, (vector_size<V> - N)>;
71+
return swizzle(std::forward<V>(input), Indices {});
72+
}
73+
74+
namespace detail {
75+
template<size_t N, size_t... Is>
76+
struct reverse_index_sequence_helper: reverse_index_sequence_helper<N - 1, Is..., N - 1> {};
77+
78+
template<size_t... Is>
79+
struct reverse_index_sequence_helper<0, Is...> {
80+
using type = index_sequence<Is...>;
81+
};
82+
} // namespace detail
83+
84+
/**
85+
* Reverses the elements in the given vector.
86+
*
87+
* # Example
88+
* ```
89+
* vec<int, 6> x = {1, 2, 3, 4, 5, 6};
90+
* vec<int, 6> y = reversed(x); // 6, 5, 4, 3, 2, 1
91+
* ```
92+
*/
93+
template<typename V>
94+
KERNEL_FLOAT_INLINE into_vector_type<V> reversed(V&& input) {
95+
using Input = into_vector_type<V>;
96+
using Output = Input;
97+
using Indices = typename detail::reverse_index_sequence_helper<vector_size<V>>::type;
98+
99+
return swizzle(std::forward<V>(input), Indices {});
100+
}
101+
102+
namespace detail {
103+
template<typename I, typename J>
104+
struct concat_index_sequence_helper {};
105+
106+
template<size_t... Is, size_t... Js>
107+
struct concat_index_sequence_helper<index_sequence<Is...>, index_sequence<Js...>> {
108+
using type = index_sequence<Is..., Js...>;
109+
};
110+
} // namespace detail
111+
112+
/**
113+
* Rotate the given vector ``K`` steps to the right. In other words, this move the front element to the back
114+
* ``K`` times. This is the inverse of ``rotate_left``.
115+
*
116+
* # Example
117+
* ```
118+
* vec<int, 6> x = {1, 2, 3, 4, 5, 6};
119+
* vec<int, 6> y = rotate_right<2>(x); // 5, 6, 1, 2, 3, 4
120+
* ```
121+
*/
122+
template<size_t K = 1, typename V>
123+
KERNEL_FLOAT_INLINE into_vector_type<V> rotate_right(V&& input) {
124+
static constexpr size_t N = vector_size<V>;
125+
static constexpr size_t I = (N > 0) ? (K % N) : 0;
126+
127+
using First = index_sequence<I, N - I>;
128+
using Second = index_sequence<N - I>;
129+
using Indices = typename detail::concat_index_sequence_helper<First, Second>::type;
130+
131+
return swizzle(std::forward<V>(input), Indices {});
132+
}
133+
134+
/**
135+
* Rotate the given vector ``K`` steps to the left. In other words, this move the back element to the front
136+
* ``K`` times. This is the inverse of ``rotate_right``.
137+
*
138+
* # Example
139+
* ```
140+
* vec<int, 6> x = {1, 2, 3, 4, 5, 6};
141+
* vec<int, 6> y = rotate_left<4>(x); // 5, 6, 1, 2, 3, 4
142+
* ```
143+
*/
144+
template<size_t K = 1, typename V>
145+
KERNEL_FLOAT_INLINE into_vector_type<V> rotate_left(V&& input) {
146+
static constexpr size_t N = vector_size<V>;
147+
static constexpr size_t K_rev = N > 0 ? (N - K % N) : 0;
148+
149+
return rotate_right<K_rev>(std::forward<V>(input));
150+
}
151+
152+
namespace detail {
153+
template<
154+
typename U,
155+
typename V,
156+
typename Is = make_index_sequence<vector_size<U>>,
157+
typename Js = make_index_sequence<vector_size<V>>>
158+
struct concat_helper;
159+
160+
template<typename U, typename V, size_t... Is, size_t... Js>
161+
struct concat_helper<U, V, index_sequence<Is...>, index_sequence<Js...>> {
162+
using type = vector_storage<
163+
common_t<vector_value_type<U>, vector_value_type<V>>,
164+
vector_size<U> + vector_size<V>>;
165+
166+
KERNEL_FLOAT_INLINE static type call(U&& left, V&& right) {
167+
return type {left.get(const_index<Is> {})..., right.get(const_index<Js> {})...};
168+
}
169+
};
170+
171+
template<typename... Ts>
172+
struct recur_concat_helper;
173+
174+
template<typename U>
175+
struct recur_concat_helper<U> {
176+
using type = U;
177+
178+
KERNEL_FLOAT_INLINE static U call(U&& input) {
179+
return output;
180+
}
181+
};
182+
183+
template<typename U, typename V, typename... Rest>
184+
struct recur_concat_helper<U, V, Rest...> {
185+
using recur_helper = recur_concat_helper<typename concat_helper<U, V>::type, Rest...>;
186+
using type = typename recur_helper::type;
187+
188+
KERNEL_FLOAT_INLINE static type call(U&& left, V&& right, Rest&&... rest) {
189+
return recur_helper::call(
190+
concat_helper<U, V>::call(std::forward<U>(left), std::forward<V>(right)),
191+
std::forward<Rest>(rest)...);
192+
}
193+
};
194+
} // namespace detail
195+
196+
template<typename... Vs>
197+
using concat_type = typename detail::recur_concat_helper<into_vector_type<Vs>...>::type;
198+
199+
/**
200+
* Concatenate the given vectors into one large vector. For example, given vectors of size 3, size 2 and size 5,
201+
* this function returns a new vector of size 3+2+5=8. If the vectors are not of the same element type, they
202+
* will first be cast into a common data type.
203+
*
204+
* # Examples
205+
* ```
206+
* vec<int, 3> x = {1, 2, 3};
207+
* int y = 4;
208+
* vec<int, 4> z = {5, 6, 7, 8};
209+
* vec<int, 8> xyz = concat(x, y, z); // 1, 2, 3, 4, 5, 6, 7, 8
210+
* ```
211+
*/
212+
template<typename... Vs>
213+
KERNEL_FLOAT_INLINE concat_type<Vs...> concat(Vs&&... inputs) {
214+
return detail::recur_concat_helper<into_vector_type<Vs>...>::call(
215+
into_vector<Vs>(std::forward<Vs>(inputs))...);
216+
}
217+
218+
} // namespace kernel_float
219+
220+
#endif //KERNEL_FLOAT_SWIZZLE_H

0 commit comments

Comments
 (0)