GLSL-like swizzling in C++20
* without #defines
* using field syntax
* supporting assignment
* without UB (I think)
https://godbolt.org/z/xY7Pxerez
godbolt.orgCompiler Explorer - C++
template<typename Base, int len>
struct Vec {
using This = Vec<Base, len>;
template <int dst_len, std::array<int, dst_len> mapping>
struct Swizzler {
operator Vec<Base, dst_len>() {
auto src = reinterpret_cast<Vec<Base, len>*>(this);
Vec<Base, dst_len> dst;
for (int i = 0; i < dst_len; i++)
dst.arr[i] = src->arr[mapping[i]];
return dst;
}
void operator=(const Vec<Base, dst_len>& src) {
auto dst = reinterpret_cast<Vec<Base, len>*>(this);
for (int i = 0; i < dst_len; i++)
dst->arr[mapping[i]] = src.arr[i];
}
};
#define COMPONENT_0 x
#define COMPONENT_1 y
#define COMPONENT_2 z
#define COMPONENT_3 w
#define CONCAT_4_(a, b, c, d) a##b##c##d
#define CONCAT_4(a, b, c, d) CONCAT_4_(a, b, c, d)
#define SWIZZLER_4(a, b, c, d) Swizzler<4, { a, b, c, d }> CONCAT_4(COMPONENT_##a, COMPONENT_##b, COMPONENT_##c, COMPONENT_##d);
#define GEN_SWIZZLERS_4_D(D, C, B, A) SWIZZLER_4(A, B, C, D)
#define GEN_SWIZZLERS_4_C(C, B, A) GEN_SWIZZLERS_4_D(0, C, B, A) GEN_SWIZZLERS_4_D(1, C, B, A) GEN_SWIZZLERS_4_D(2, C, B, A) GEN_SWIZZLERS_4_D(3, C, B, A)
#define GEN_SWIZZLERS_4_B(B, A) GEN_SWIZZLERS_4_C(0, B, A) GEN_SWIZZLERS_4_C(1, B, A) GEN_SWIZZLERS_4_C(2, B, A) GEN_SWIZZLERS_4_C(3, B, A)
#define GEN_SWIZZLERS_4_A(A) GEN_SWIZZLERS_4_B(0, A) GEN_SWIZZLERS_4_B(1, A) GEN_SWIZZLERS_4_B(2, A) GEN_SWIZZLERS_4_B(3, A)
#define GEN_SWIZZLERS_4() GEN_SWIZZLERS_4_A(0) GEN_SWIZZLERS_4_A(1) GEN_SWIZZLERS_4_A(2) GEN_SWIZZLERS_4_A(3)
#define CONCAT_3_(a, b, c) a##b##c
#define CONCAT_3(a, b, c) CONCAT_3_(a, b, c)
#define SWIZZLER_3(a, b, c) Swizzler<3, { a, b, c }> CONCAT_3(COMPONENT_##a, COMPONENT_##b, COMPONENT_##c);
#define GEN_SWIZZLERS_3_C(C, B, A) SWIZZLER_3(A, B, C)
#define GEN_SWIZZLERS_3_B(B, A) GEN_SWIZZLERS_3_C(0, B, A) GEN_SWIZZLERS_3_C(1, B, A) GEN_SWIZZLERS_3_C(2, B, A) GEN_SWIZZLERS_3_C(3, B, A)
#define GEN_SWIZZLERS_3_A(A) GEN_SWIZZLERS_3_B(0, A) GEN_SWIZZLERS_3_B(1, A) GEN_SWIZZLERS_3_B(2, A) GEN_SWIZZLERS_3_B(3, A)
#define GEN_SWIZZLERS_3() GEN_SWIZZLERS_3_A(0) GEN_SWIZZLERS_3_A(1) GEN_SWIZZLERS_3_A(2) GEN_SWIZZLERS_3_A(3)
#define CONCAT_2_(a, b) a##b
#define CONCAT_2(a, b) CONCAT_2_(a, b)
#define SWIZZLER_2(a, b) Swizzler<2, { a, b }> CONCAT_2(COMPONENT_##a, COMPONENT_##b);
#define GEN_SWIZZLERS_2_B(B, A) SWIZZLER_2(A, B)
#define GEN_SWIZZLERS_2_A(A) GEN_SWIZZLERS_2_B(0, A) GEN_SWIZZLERS_2_B(1, A) GEN_SWIZZLERS_2_B(2, A) GEN_SWIZZLERS_2_B(3, A)
#define GEN_SWIZZLERS_2() GEN_SWIZZLERS_2_A(0) GEN_SWIZZLERS_2_A(1) GEN_SWIZZLERS_2_A(2) GEN_SWIZZLERS_2_A(3)
#define SWIZZLER_1(a) Swizzler<1, { a }> COMPONENT_##a;
#define GEN_SWIZZLERS_1_A(A) SWIZZLER_1(A)
#define GEN_SWIZZLERS_1() GEN_SWIZZLERS_1_A(0) GEN_SWIZZLERS_1_A(1) GEN_SWIZZLERS_1_A(2) GEN_SWIZZLERS_1_A(3)
union {
GEN_SWIZZLERS_4()
GEN_SWIZZLERS_3()
GEN_SWIZZLERS_2()
GEN_SWIZZLERS_1()
Base arr[len];
};
};
using Vec4 = Vec<float, 4>;
using Vec4i = Vec<int, 4>;
static_assert(sizeof(Vec4) == sizeof(float) * 4);
static_assert(sizeof(Vec4i) == sizeof(int) * 4);
Vec4 foo(Vec4 v) {
return v.xyxy;
}
Vec4i fooi(Vec4i v) {
return v.xyxy;
}
void bar(Vec4& v) {
v.xy = v.zw;
}