]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - Vc/include/Vc/common/operators.h
Vc package added (version 0.6.79-dev)
[u/mrichter/AliRoot.git] / Vc / include / Vc / common / operators.h
diff --git a/Vc/include/Vc/common/operators.h b/Vc/include/Vc/common/operators.h
new file mode 100644 (file)
index 0000000..e792cae
--- /dev/null
@@ -0,0 +1,209 @@
+#ifndef VC_ICC
+// ICC ICEs if the following type-traits are in the anonymous namespace
+namespace
+{
+#endif
+template<typename Cond, typename T> struct EnableIfNeitherIntegerNorVector : public EnableIf<!CanConvertToInt<Cond>::Value, T> {};
+template<typename Cond, typename T> struct EnableIfNeitherIntegerNorVector<Vector<Cond>, T>;
+
+template<typename T> struct IsVector             { enum { Value = false }; };
+template<typename T> struct IsVector<Vector<T> > { enum { Value =  true }; };
+
+template<typename T0, typename T1, typename V0, typename V1> struct IsTypeCombinationOf
+{
+    enum {
+        Value = IsVector<V0>::Value ? (IsVector<V1>::Value ? ( // Vec × Vec
+                    (    IsEqualType<T0, V0>::Value && HasImplicitCast<T1, V1>::Value && !HasImplicitCast<T1, int>::Value) ||
+                    (HasImplicitCast<T0, V0>::Value &&     IsEqualType<T1, V1>::Value && !HasImplicitCast<T0, int>::Value) ||
+                    (    IsEqualType<T0, V1>::Value && HasImplicitCast<T1, V0>::Value && !HasImplicitCast<T1, int>::Value) ||
+                    (HasImplicitCast<T0, V1>::Value &&     IsEqualType<T1, V0>::Value && !HasImplicitCast<T0, int>::Value)
+                ) : ( // Vec × Scalar
+                    (HasImplicitCast<T0, V0>::Value &&     IsEqualType<T1, V1>::Value && !HasImplicitCast<T0, int>::Value) ||
+                    (    IsEqualType<T0, V1>::Value && HasImplicitCast<T1, V0>::Value && !HasImplicitCast<T1, int>::Value)
+            )) : (IsVector<V1>::Value ? ( // Scalar × Vec
+                    (    IsEqualType<T0, V0>::Value && HasImplicitCast<T1, V1>::Value && !HasImplicitCast<T1, int>::Value) ||
+                    (HasImplicitCast<T0, V1>::Value &&     IsEqualType<T1, V0>::Value && !HasImplicitCast<T0, int>::Value)
+                ) : ( // Scalar × Scalar
+                    (    IsEqualType<T0, V0>::Value &&     IsEqualType<T1, V1>::Value) ||
+                    (    IsEqualType<T0, V1>::Value &&     IsEqualType<T1, V0>::Value)
+                    ))
+    };
+};
+
+template<typename T0, typename T1, typename V> struct IsVectorOperands
+{
+    enum {
+        Value = (HasImplicitCast<T0, V>::Value && !HasImplicitCast<T0, int>::Value && !IsEqualType<T0, V>::Value && IsEqualType<T1, V>::Value)
+            ||  (HasImplicitCast<T1, V>::Value && !HasImplicitCast<T1, int>::Value && !IsEqualType<T1, V>::Value && IsEqualType<T0, V>::Value)
+    };
+};
+#ifndef VC_ICC
+}
+#endif
+
+// float-int arithmetic operators //{{{1
+// These operators must be very picky about the exact types they want to handle. Once (uncontrolled)
+// implicit type conversions get involved, ambiguous overloads will occur. E.g. a simple int × enum
+// will become ambiguous because it can convert both to a vector type, which then can execute the
+// operator. We can't argue that such code should not be used - it could break existing code, not
+// under control of the developer, just by putting the Vc header somewhere on top.
+//
+// The following type combinations are safe (always symmetric):
+// 1. Vector × Vector
+// 2. Vector × Scalar (int, float, enum value, ...)
+// 3. Some object that has a vector cast operator × Vector
+// 4. Some object that has a vector cast operator × Scalar
+//
+// Additionally there are restrictions on which types combine to what resulting type:
+// 1.a.        float × double_v -> double_v
+// 1.b.      any int × double_v -> double_v
+// 2.a.     (u)int_v ×  float_v ->  float_v
+// 2.b.     (u)int_v ×    float ->  float_v
+// 2.c.      any int ×  float_v ->  float_v
+// 3.a.   (u)short_v × sfloat_v -> sfloat_v
+// 3.b.   (u)short_v ×    float -> sfloat_v
+// 3.c.        short × sfloat_v -> sfloat_v
+// 4.a.        int_v ×   uint_v ->   uint_v
+// 4.b.      any int ×   uint_v ->   uint_v
+// 4.c. unsigned int ×    int_v ->   uint_v
+// 4.d.   signed int ×    int_v ->    int_v
+// 5.              shorts like ints
+
+#define VC_OPERATOR_FORWARD_(ret, op) \
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, double_v>::Value || \
+    ((IsEqualType<T0, float>::Value || IsLikeInteger<T0>::Value) && HasImplicitCast<T1, double_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    ((IsEqualType<T1, float>::Value || IsLikeInteger<T1>::Value) && HasImplicitCast<T0, double_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, double_##ret>::Value operator op(const T0 &x, const T1 &y) { return double_v(x) op double_v(y); } \
+\
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, float_v>::Value || \
+    IsTypeCombinationOf<T0, T1,  int_v, float_v>::Value || \
+    IsTypeCombinationOf<T0, T1, uint_v, float_v>::Value || \
+    IsTypeCombinationOf<T0, T1,  int_v,   float>::Value || \
+    IsTypeCombinationOf<T0, T1, uint_v,   float>::Value || \
+    (IsLikeInteger<T0>::Value && HasImplicitCast<T1, float_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeInteger<T1>::Value && HasImplicitCast<T0, float_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, float_##ret>::Value operator op(const T0 &x, const T1 &y) { return float_v(x) op float_v(y); } \
+\
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, sfloat_v>::Value || \
+    IsTypeCombinationOf<T0, T1,  short_v, sfloat_v>::Value || \
+    IsTypeCombinationOf<T0, T1, ushort_v, sfloat_v>::Value || \
+    IsTypeCombinationOf<T0, T1,  short_v,    float>::Value || \
+    IsTypeCombinationOf<T0, T1, ushort_v,    float>::Value || \
+    (IsLikeInteger<T0>::Value && HasImplicitCast<T1, sfloat_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeInteger<T1>::Value && HasImplicitCast<T0, sfloat_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, sfloat_##ret>::Value operator op(const T0 &x, const T1 &y) { return sfloat_v(x) op sfloat_v(y); } \
+\
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, uint_v>::Value || \
+    IsTypeCombinationOf<T0, T1, int_v, uint_v>::Value || \
+    (IsUnsignedInteger<T0>::Value && HasImplicitCast<T1, int_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsUnsignedInteger<T1>::Value && HasImplicitCast<T0, int_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    (IsLikeInteger<T0>::Value && !IsEqualType<T0, unsigned int>::Value && HasImplicitCast<T1, uint_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeInteger<T1>::Value && !IsEqualType<T1, unsigned int>::Value && HasImplicitCast<T0, uint_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, uint_##ret>::Value operator op(const T0 &x, const T1 &y) { return uint_v(x) op uint_v(y); } \
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, int_v>::Value || \
+    (IsLikeSignedInteger<T0>::Value && !IsEqualType<T0, int>::Value && HasImplicitCast<T1, int_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeSignedInteger<T1>::Value && !IsEqualType<T1, int>::Value && HasImplicitCast<T0, int_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, int_##ret>::Value operator op(const T0 &x, const T1 &y) { return  int_v(x) op  int_v(y); } \
+\
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, ushort_v>::Value || \
+    IsTypeCombinationOf<T0, T1, short_v, ushort_v>::Value || \
+    (IsUnsignedInteger<T0>::Value && HasImplicitCast<T1, short_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsUnsignedInteger<T1>::Value && HasImplicitCast<T0, short_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    (IsLikeInteger<T0>::Value && !IsEqualType<T0, unsigned short>::Value && HasImplicitCast<T1, ushort_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeInteger<T1>::Value && !IsEqualType<T1, unsigned short>::Value && HasImplicitCast<T0, ushort_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, ushort_##ret>::Value operator op(const T0 &x, const T1 &y) { return ushort_v(x) op ushort_v(y); } \
+template<typename T0, typename T1> static inline typename EnableIf< \
+    IsVectorOperands<T0, T1, short_v>::Value || \
+    (IsLikeSignedInteger<T0>::Value && !IsEqualType<T0, short>::Value && HasImplicitCast<T1, short_v>::Value && !HasImplicitCast<T1, int>::Value) || \
+    (IsLikeSignedInteger<T1>::Value && !IsEqualType<T1, short>::Value && HasImplicitCast<T0, short_v>::Value && !HasImplicitCast<T0, int>::Value) || \
+    false, short_##ret>::Value operator op(const T0 &x, const T1 &y) { return  short_v(x) op  short_v(y); }
+
+
+// break incorrect combinations
+#define VC_OPERATOR_INTENTIONAL_ERROR_1(V, op) \
+template<typename T> static inline typename EnableIfNeitherIntegerNorVector<T, Vc::Error::invalid_operands_of_types<V, T> >::Value operator op(const V &, const T &) { return Vc::Error::invalid_operands_of_types<V, T>(); } \
+template<typename T> static inline typename EnableIfNeitherIntegerNorVector<T, Vc::Error::invalid_operands_of_types<T, V> >::Value operator op(const T &, const V &) { return Vc::Error::invalid_operands_of_types<T, V>(); }
+
+#define VC_OPERATOR_INTENTIONAL_ERROR_2(V1, V2, op) \
+static inline Vc::Error::invalid_operands_of_types<V1, V2> operator op(V1::AsArg, V2::AsArg) { return Vc::Error::invalid_operands_of_types<V1, V2>(); } \
+static inline Vc::Error::invalid_operands_of_types<V2, V1> operator op(V2::AsArg, V1::AsArg) { return Vc::Error::invalid_operands_of_types<V2, V1>(); }
+
+#define VC_OPERATOR_INTENTIONAL_ERROR_3(V, _T, op) \
+template<typename T> static inline typename EnableIf<IsEqualType<T, _T>::Value, Vc::Error::invalid_operands_of_types<V, T> >::Value operator op(const V &, const T &) { return Vc::Error::invalid_operands_of_types<V, T>(); } \
+template<typename T> static inline typename EnableIf<IsEqualType<T, _T>::Value, Vc::Error::invalid_operands_of_types<T, V> >::Value operator op(const T &, const V &) { return Vc::Error::invalid_operands_of_types<T, V>(); }
+
+//#define VC_EXTRA_CHECKING
+#ifdef VC_EXTRA_CHECKING
+#define VC_OPERATOR_INTENTIONAL_ERROR(op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v, sfloat_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v,  float_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v,    int_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v,   uint_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v,  short_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(double_v, ushort_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(   int_v,  short_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(  uint_v,  short_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(   int_v, ushort_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(  uint_v, ushort_v, op) \
+    VC_APPLY_1(VC_LIST_VECTOR_TYPES, VC_OPERATOR_INTENTIONAL_ERROR_1, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2( float_v,  short_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2( float_v, ushort_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(sfloat_v,  float_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(sfloat_v,    int_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_2(sfloat_v,   uint_v, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_3( float_v,   double, op) \
+    VC_OPERATOR_INTENTIONAL_ERROR_3(sfloat_v,   double, op)
+#else
+#define VC_OPERATOR_INTENTIONAL_ERROR(op)
+#endif
+
+#define VC_OPERATOR_FORWARD_COMMUTATIVE(ret, op, op2) \
+template<typename T> static inline VC_EXACT_TYPE(T,         double, double_##ret) operator op(T x, double_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          float, sfloat_##ret) operator op(T x, sfloat_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          float,  float_##ret) operator op(T x,  float_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T,            int,    int_##ret) operator op(T x,    int_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T,   unsigned int,   uint_##ret) operator op(T x,   uint_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          short,  short_##ret) operator op(T x,  short_v::AsArg y) { return y op2 x; } \
+template<typename T> static inline VC_EXACT_TYPE(T, unsigned short, ushort_##ret) operator op(T x, ushort_v::AsArg y) { return y op2 x; } \
+VC_OPERATOR_FORWARD_(ret, op) \
+VC_OPERATOR_INTENTIONAL_ERROR(op)
+
+#define VC_OPERATOR_FORWARD(ret, op) \
+template<typename T> static inline VC_EXACT_TYPE(T,         double, double_##ret) operator op(T x, double_v::AsArg y) { return double_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          float, sfloat_##ret) operator op(T x, sfloat_v::AsArg y) { return sfloat_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          float,  float_##ret) operator op(T x,  float_v::AsArg y) { return  float_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T,            int,    int_##ret) operator op(T x,    int_v::AsArg y) { return    int_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T,   unsigned int,   uint_##ret) operator op(T x,   uint_v::AsArg y) { return   uint_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T,          short,  short_##ret) operator op(T x,  short_v::AsArg y) { return  short_v(x) op y; } \
+template<typename T> static inline VC_EXACT_TYPE(T, unsigned short, ushort_##ret) operator op(T x, ushort_v::AsArg y) { return ushort_v(x) op y; } \
+VC_OPERATOR_FORWARD_(ret, op) \
+VC_OPERATOR_INTENTIONAL_ERROR(op)
+
+VC_OPERATOR_FORWARD_COMMUTATIVE(v, *, *)
+VC_OPERATOR_FORWARD(v, /)
+VC_OPERATOR_FORWARD_COMMUTATIVE(v, +, +)
+VC_OPERATOR_FORWARD(v, -)
+VC_OPERATOR_FORWARD_COMMUTATIVE(v, |, |)
+VC_OPERATOR_FORWARD_COMMUTATIVE(v, &, &)
+VC_OPERATOR_FORWARD_COMMUTATIVE(v, ^, ^)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, <, >)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, >, <)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, <=, >=)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, >=, <=)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, ==, ==)
+VC_OPERATOR_FORWARD_COMMUTATIVE(m, !=, !=)
+
+#undef VC_OPERATOR_FORWARD_
+#undef VC_OPERATOR_INTENTIONAL_ERROR_1
+#undef VC_OPERATOR_INTENTIONAL_ERROR_2
+#undef VC_OPERATOR_INTENTIONAL_ERROR
+#undef VC_OPERATOR_FORWARD_COMMUTATIVE
+#undef VC_OPERATOR_FORWARD
+
+// }}}1