skvx: allow more implicit conversions

Guarding the implict constructors and scalar/vector
operations with std::is_convertible ought to make SkVx
types feel more like normal C types, allowing implicit
conversions exactly when the scalar equivalents would.

This shouldn't change the behavior of any code, or make
anything new possible... just nicer to read and write.

Change-Id: Iff4b89012c5b8c7f7933e6841c925b81186bc614
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201402
Commit-Queue: Mike Klein <mtklein@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2019-03-14 13:30:42 -05:00 committed by Skia Commit-Bot
parent a89cc05162
commit f4438d56e9
2 changed files with 68 additions and 48 deletions

View File

@ -49,7 +49,10 @@ struct Vec {
// Other operations on Vec should be defined outside the type.
Vec() = default;
Vec(T x) : lo(x), hi(x) {}
template <typename U,
typename=typename std::enable_if<std::is_convertible<U,T>::value>::type>
Vec(U x) : lo(x), hi(x) {}
Vec(std::initializer_list<T> xs) {
T vals[N] = {0};
@ -77,7 +80,10 @@ struct Vec<1,T> {
T val;
Vec() = default;
Vec(T x) : val(x) {}
template <typename U,
typename=typename std::enable_if<std::is_convertible<U,T>::value>::type>
Vec(U x) : val(x) {}
Vec(std::initializer_list<T> xs) : val(xs.size() ? *xs.begin() : 0) {}
@ -101,9 +107,12 @@ struct Vec<1,T> {
#endif
// Helps tamp down on the repetitive boilerplate.
#define SINT template <int N, typename T> static inline
#define SIT template < typename T> static inline
#define SI static inline
#define SI static inline
#define SIT template < typename T> static inline
#define SINT template <int N, typename T> static inline
#define SINTU template <int N, typename T, typename U, \
typename=typename std::enable_if<std::is_convertible<U,T>::value>::type> \
static inline
template <typename D, typename S>
SI D bit_pun(S s) {
@ -296,46 +305,46 @@ SINT Vec<N,T> mad(Vec<N,T> f,
// Scalar/vector operations just splat the scalar to a vector...
SINT Vec<N,T> operator+ (T x, Vec<N,T> y) { return Vec<N,T>(x) + y; }
SINT Vec<N,T> operator- (T x, Vec<N,T> y) { return Vec<N,T>(x) - y; }
SINT Vec<N,T> operator* (T x, Vec<N,T> y) { return Vec<N,T>(x) * y; }
SINT Vec<N,T> operator/ (T x, Vec<N,T> y) { return Vec<N,T>(x) / y; }
SINT Vec<N,T> operator^ (T x, Vec<N,T> y) { return Vec<N,T>(x) ^ y; }
SINT Vec<N,T> operator& (T x, Vec<N,T> y) { return Vec<N,T>(x) & y; }
SINT Vec<N,T> operator| (T x, Vec<N,T> y) { return Vec<N,T>(x) | y; }
SINT Vec<N,M<T>> operator==(T x, Vec<N,T> y) { return Vec<N,T>(x) == y; }
SINT Vec<N,M<T>> operator!=(T x, Vec<N,T> y) { return Vec<N,T>(x) != y; }
SINT Vec<N,M<T>> operator<=(T x, Vec<N,T> y) { return Vec<N,T>(x) <= y; }
SINT Vec<N,M<T>> operator>=(T x, Vec<N,T> y) { return Vec<N,T>(x) >= y; }
SINT Vec<N,M<T>> operator< (T x, Vec<N,T> y) { return Vec<N,T>(x) < y; }
SINT Vec<N,M<T>> operator> (T x, Vec<N,T> y) { return Vec<N,T>(x) > y; }
SINT Vec<N,T> min(T x, Vec<N,T> y) { return min(Vec<N,T>(x), y); }
SINT Vec<N,T> max(T x, Vec<N,T> y) { return max(Vec<N,T>(x), y); }
SINTU Vec<N,T> operator+ (U x, Vec<N,T> y) { return Vec<N,T>(x) + y; }
SINTU Vec<N,T> operator- (U x, Vec<N,T> y) { return Vec<N,T>(x) - y; }
SINTU Vec<N,T> operator* (U x, Vec<N,T> y) { return Vec<N,T>(x) * y; }
SINTU Vec<N,T> operator/ (U x, Vec<N,T> y) { return Vec<N,T>(x) / y; }
SINTU Vec<N,T> operator^ (U x, Vec<N,T> y) { return Vec<N,T>(x) ^ y; }
SINTU Vec<N,T> operator& (U x, Vec<N,T> y) { return Vec<N,T>(x) & y; }
SINTU Vec<N,T> operator| (U x, Vec<N,T> y) { return Vec<N,T>(x) | y; }
SINTU Vec<N,M<T>> operator==(U x, Vec<N,T> y) { return Vec<N,T>(x) == y; }
SINTU Vec<N,M<T>> operator!=(U x, Vec<N,T> y) { return Vec<N,T>(x) != y; }
SINTU Vec<N,M<T>> operator<=(U x, Vec<N,T> y) { return Vec<N,T>(x) <= y; }
SINTU Vec<N,M<T>> operator>=(U x, Vec<N,T> y) { return Vec<N,T>(x) >= y; }
SINTU Vec<N,M<T>> operator< (U x, Vec<N,T> y) { return Vec<N,T>(x) < y; }
SINTU Vec<N,M<T>> operator> (U x, Vec<N,T> y) { return Vec<N,T>(x) > y; }
SINTU Vec<N,T> min(U x, Vec<N,T> y) { return min(Vec<N,T>(x), y); }
SINTU Vec<N,T> max(U x, Vec<N,T> y) { return max(Vec<N,T>(x), y); }
// ... and same deal for vector/scalar operations.
SINT Vec<N,T> operator+ (Vec<N,T> x, T y) { return x + Vec<N,T>(y); }
SINT Vec<N,T> operator- (Vec<N,T> x, T y) { return x - Vec<N,T>(y); }
SINT Vec<N,T> operator* (Vec<N,T> x, T y) { return x * Vec<N,T>(y); }
SINT Vec<N,T> operator/ (Vec<N,T> x, T y) { return x / Vec<N,T>(y); }
SINT Vec<N,T> operator^ (Vec<N,T> x, T y) { return x ^ Vec<N,T>(y); }
SINT Vec<N,T> operator& (Vec<N,T> x, T y) { return x & Vec<N,T>(y); }
SINT Vec<N,T> operator| (Vec<N,T> x, T y) { return x | Vec<N,T>(y); }
SINT Vec<N,M<T>> operator==(Vec<N,T> x, T y) { return x == Vec<N,T>(y); }
SINT Vec<N,M<T>> operator!=(Vec<N,T> x, T y) { return x != Vec<N,T>(y); }
SINT Vec<N,M<T>> operator<=(Vec<N,T> x, T y) { return x <= Vec<N,T>(y); }
SINT Vec<N,M<T>> operator>=(Vec<N,T> x, T y) { return x >= Vec<N,T>(y); }
SINT Vec<N,M<T>> operator< (Vec<N,T> x, T y) { return x < Vec<N,T>(y); }
SINT Vec<N,M<T>> operator> (Vec<N,T> x, T y) { return x > Vec<N,T>(y); }
SINT Vec<N,T> min(Vec<N,T> x, T y) { return min(x, Vec<N,T>(y)); }
SINT Vec<N,T> max(Vec<N,T> x, T y) { return max(x, Vec<N,T>(y)); }
SINTU Vec<N,T> operator+ (Vec<N,T> x, U y) { return x + Vec<N,T>(y); }
SINTU Vec<N,T> operator- (Vec<N,T> x, U y) { return x - Vec<N,T>(y); }
SINTU Vec<N,T> operator* (Vec<N,T> x, U y) { return x * Vec<N,T>(y); }
SINTU Vec<N,T> operator/ (Vec<N,T> x, U y) { return x / Vec<N,T>(y); }
SINTU Vec<N,T> operator^ (Vec<N,T> x, U y) { return x ^ Vec<N,T>(y); }
SINTU Vec<N,T> operator& (Vec<N,T> x, U y) { return x & Vec<N,T>(y); }
SINTU Vec<N,T> operator| (Vec<N,T> x, U y) { return x | Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator==(Vec<N,T> x, U y) { return x == Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator!=(Vec<N,T> x, U y) { return x != Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator<=(Vec<N,T> x, U y) { return x <= Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator>=(Vec<N,T> x, U y) { return x >= Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator< (Vec<N,T> x, U y) { return x < Vec<N,T>(y); }
SINTU Vec<N,M<T>> operator> (Vec<N,T> x, U y) { return x > Vec<N,T>(y); }
SINTU Vec<N,T> min(Vec<N,T> x, U y) { return min(x, Vec<N,T>(y)); }
SINTU Vec<N,T> max(Vec<N,T> x, U y) { return max(x, Vec<N,T>(y)); }
// All vector/scalar combinations for mad() with at least one vector.
SINT Vec<N,T> mad(T f, Vec<N,T> m, Vec<N,T> a) { return Vec<N,T>(f)*m + a; }
SINT Vec<N,T> mad(Vec<N,T> f, T m, Vec<N,T> a) { return f*Vec<N,T>(m) + a; }
SINT Vec<N,T> mad(Vec<N,T> f, Vec<N,T> m, T a) { return f*m + Vec<N,T>(a); }
SINT Vec<N,T> mad(Vec<N,T> f, T m, T a) { return f*Vec<N,T>(m) + Vec<N,T>(a); }
SINT Vec<N,T> mad(T f, Vec<N,T> m, T a) { return Vec<N,T>(f)*m + Vec<N,T>(a); }
SINT Vec<N,T> mad(T f, T m, Vec<N,T> a) { return Vec<N,T>(f)*Vec<N,T>(m) + a; }
SINTU Vec<N,T> mad(U f, Vec<N,T> m, Vec<N,T> a) { return Vec<N,T>(f)*m + a; }
SINTU Vec<N,T> mad(Vec<N,T> f, U m, Vec<N,T> a) { return f*Vec<N,T>(m) + a; }
SINTU Vec<N,T> mad(Vec<N,T> f, Vec<N,T> m, U a) { return f*m + Vec<N,T>(a); }
SINTU Vec<N,T> mad(Vec<N,T> f, U m, U a) { return f*Vec<N,T>(m) + Vec<N,T>(a); }
SINTU Vec<N,T> mad(U f, Vec<N,T> m, U a) { return Vec<N,T>(f)*m + Vec<N,T>(a); }
SINTU Vec<N,T> mad(U f, U m, Vec<N,T> a) { return Vec<N,T>(f)*Vec<N,T>(m) + a; }
// The various op= operators, for vectors...
SINT Vec<N,T>& operator+=(Vec<N,T>& x, Vec<N,T> y) { return (x = x + y); }
@ -347,13 +356,13 @@ SINT Vec<N,T>& operator&=(Vec<N,T>& x, Vec<N,T> y) { return (x = x & y); }
SINT Vec<N,T>& operator|=(Vec<N,T>& x, Vec<N,T> y) { return (x = x | y); }
// ... for scalars...
SINT Vec<N,T>& operator+=(Vec<N,T>& x, T y) { return (x = x + Vec<N,T>(y)); }
SINT Vec<N,T>& operator-=(Vec<N,T>& x, T y) { return (x = x - Vec<N,T>(y)); }
SINT Vec<N,T>& operator*=(Vec<N,T>& x, T y) { return (x = x * Vec<N,T>(y)); }
SINT Vec<N,T>& operator/=(Vec<N,T>& x, T y) { return (x = x / Vec<N,T>(y)); }
SINT Vec<N,T>& operator^=(Vec<N,T>& x, T y) { return (x = x ^ Vec<N,T>(y)); }
SINT Vec<N,T>& operator&=(Vec<N,T>& x, T y) { return (x = x & Vec<N,T>(y)); }
SINT Vec<N,T>& operator|=(Vec<N,T>& x, T y) { return (x = x | Vec<N,T>(y)); }
SINTU Vec<N,T>& operator+=(Vec<N,T>& x, U y) { return (x = x + Vec<N,T>(y)); }
SINTU Vec<N,T>& operator-=(Vec<N,T>& x, U y) { return (x = x - Vec<N,T>(y)); }
SINTU Vec<N,T>& operator*=(Vec<N,T>& x, U y) { return (x = x * Vec<N,T>(y)); }
SINTU Vec<N,T>& operator/=(Vec<N,T>& x, U y) { return (x = x / Vec<N,T>(y)); }
SINTU Vec<N,T>& operator^=(Vec<N,T>& x, U y) { return (x = x ^ Vec<N,T>(y)); }
SINTU Vec<N,T>& operator&=(Vec<N,T>& x, U y) { return (x = x & Vec<N,T>(y)); }
SINTU Vec<N,T>& operator|=(Vec<N,T>& x, U y) { return (x = x | Vec<N,T>(y)); }
// ... and for shifts.
SINT Vec<N,T>& operator<<=(Vec<N,T>& x, int bits) { return (x = x << bits); }
@ -434,6 +443,7 @@ namespace skvx {
} // namespace skvx
#endif // !defined(SKNX_NO_SIMD)
#undef SINTU
#undef SINT
#undef SIT
#undef SI

View File

@ -132,4 +132,14 @@ DEF_TEST(SkVx, r) {
REPORTER_ASSERT(r, all(shuffle<2,1> (float4{1,2,3,4}) == float2{3,2}));
REPORTER_ASSERT(r, all(shuffle<2,1,2,1,2,1,2,1>(float4{1,2,3,4}) == float8{3,2,3,2,3,2,3,2}));
REPORTER_ASSERT(r, all(shuffle<3,3,3,3> (float4{1,2,3,4}) == float4{4,4,4,4}));
// Test that mixed types can be used where they make sense. Mostly about ergonomics.
REPORTER_ASSERT(r, all(float4{1,2,3,4} < 5));
REPORTER_ASSERT(r, all( byte4{1,2,3,4} < 5));
REPORTER_ASSERT(r, all( int4{1,2,3,4} < 5.0f));
float4 five = 5;
REPORTER_ASSERT(r, all(five == 5.0f));
REPORTER_ASSERT(r, all(five == 5));
REPORTER_ASSERT(r, all(max(2, min(float4{1,2,3,4}, 3)) == float4{2,2,3,3}));
}