Created
January 31, 2021 03:51
-
-
Save mattleibow/0974824b9c9e8fdb7079af56f8795207 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// All Vec have the same simple memory layout, the same as `T vec[N]`. | |
template <int N, typename T> | |
struct alignas(N * sizeof(T)) Vec { | |
static_assert((N& (N - 1)) == 0, "N must be a power of 2."); | |
static_assert(sizeof(T) >= alignof(T), "What kind of crazy T is this?"); | |
Vec<N / 2, T> lo, hi; | |
// Methods belong here in the class declaration of Vec only if: | |
// - they must be here, like constructors or operator[]; | |
// - they'll definitely never want a specialized implementation. | |
// Other operations on Vec should be defined outside the type. | |
__forceinline Vec() = default; | |
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> | |
__forceinline | |
Vec(U x) : lo(x), hi(x) {} | |
__forceinline Vec(std::initializer_list<T> xs) { | |
T vals[N] = { 0 }; | |
memcpy(vals, xs.begin(), std::min(xs.size(), (size_t)N) * sizeof(T)); | |
lo = Vec<N / 2, T>::Load(vals + 0); | |
hi = Vec<N / 2, T>::Load(vals + N / 2); | |
} | |
__forceinline T operator[](int i) const { return i < N / 2 ? lo[i] : hi[i - N / 2]; } | |
__forceinline T& operator[](int i) { return i < N / 2 ? lo[i] : hi[i - N / 2]; } | |
__forceinline static Vec Load(const void* ptr) { | |
Vec v; | |
memcpy(&v, ptr, sizeof(Vec)); | |
return v; | |
} | |
__forceinline void store(void* ptr) const { | |
memcpy(ptr, this, sizeof(Vec)); | |
} | |
}; | |
template <typename T> | |
struct Vec<1, T> { | |
T val; | |
__forceinline Vec() = default; | |
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> | |
__forceinline | |
Vec(U x) : val(x) {} | |
__forceinline Vec(std::initializer_list<T> xs) : val(xs.size() ? *xs.begin() : 0) {} | |
__forceinline T operator[](int) const { return val; } | |
__forceinline T& operator[](int) { return val; } | |
__forceinline static Vec Load(const void* ptr) { | |
Vec v; | |
memcpy(&v, ptr, sizeof(Vec)); | |
return v; | |
} | |
__forceinline void store(void* ptr) const { | |
memcpy(ptr, this, sizeof(Vec)); | |
} | |
}; | |
class GrVectorXform { | |
public: | |
using float2 = Vec<2, float>; | |
using float4 = Vec<4, float>; | |
explicit GrVectorXform() : fType(Type::kIdentity) {} | |
float2 operator()(float2 vector) const { | |
switch (fType) { | |
case Type::kIdentity: | |
return vector; | |
} | |
} | |
float4 operator()(float4 vectors) const { | |
switch (fType) { | |
case Type::kIdentity: | |
return vectors; | |
} | |
} | |
private: | |
enum class Type { kIdentity, kScale, kAffine } fType; | |
union { float2 fScaleXY, fScaleXSkewY; }; | |
float2 fSkewXScaleY; | |
float4 fScaleXYXY; | |
float4 fSkewXYXY; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I get an error on line 78 when building with ARM. x86, x64 and ARM64 are all good.