Vc  1.4.2
SIMD Vector Classes for C++
operators.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2012-2016 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef COMMON_OPERATORS_H_
29 #define COMMON_OPERATORS_H_
30 #include "simdarray.h"
31 #include "macros.h"
32 
33 namespace Vc_VERSIONED_NAMESPACE
34 {
35 namespace Detail
36 {
37 template <typename T, typename Abi, typename U>
38 enable_if<!std::is_same<T, U>::value, U> is_convertible_to_any_vector(Vector<U, Abi>);
39 template <typename T, typename Abi> T is_convertible_to_any_vector(Vector<T, Abi>);
40 
41 template <typename T, typename U, bool = std::is_integral<T>::value,
42  bool = std::is_integral<U>::value>
43 struct FundamentalReturnType;
44 template <class T, class U>
45 using fundamental_return_t = typename FundamentalReturnType<T, U>::type;
46 
47 template <typename T, typename U> struct FundamentalReturnType<T, U, false, false> {
48  using type = typename std::conditional<
49  std::is_arithmetic<U>::value,
50  typename std::conditional<(sizeof(T) < sizeof(U)), U, T>::type,
51  // U is not arithmetic, e.g. an enum or a type with e.g. operator int()
52  T>::type;
53 };
54 template <typename T, typename U> struct FundamentalReturnType<T, U, true, false> {
55  using type = typename std::conditional<
56  std::is_arithmetic<U>::value, U,
57  // U is not arithmetic, e.g. an enum or a type with e.g. operator int()
58  T>::type;
59 };
60 template <typename T, typename U> struct FundamentalReturnType<T, U, false, true> {
61  using type = T;
62 };
63 
64 template <typename T> struct my_make_signed : public std::make_signed<T> {
65 };
66 template <> struct my_make_signed<bool> {
67  using type = bool;
68 };
69 
70 template <typename TT, typename UU>
71 struct higher_conversion_rank {
72  template <typename A>
73  using fix_sign =
74  typename std::conditional<(std::is_unsigned<TT>::value ||
75  std::is_unsigned<UU>::value),
76  typename std::make_unsigned<A>::type, A>::type;
77  using T = typename my_make_signed<TT>::type;
78  using U = typename my_make_signed<UU>::type;
79  template <typename Test, typename Otherwise>
80  using c = typename std::conditional<std::is_same<T, Test>::value ||
81  std::is_same<U, Test>::value,
82  Test, Otherwise>::type;
83 
84  using type = fix_sign<c<long long, c<long, c<int, c<short, c<signed char, void>>>>>>;
85 };
86 
87 template <typename T, typename U> struct FundamentalReturnType<T, U, true, true> {
88  template <bool B, class Then, class E>
89  using c = typename std::conditional<B, Then, E>::type;
90  using type =
91  c<(sizeof(T) > sizeof(U)), T,
92  c<(sizeof(T) < sizeof(U)), U, typename higher_conversion_rank<T, U>::type>>;
93 };
94 
95 template <class V, class T, class Tq, class = void> struct ReturnTypeImpl {
96  // no type => SFINAE
97 };
98 // 1. Vector × Vector
99 template <class T, class U, class Abi, class Uq>
100 struct ReturnTypeImpl<Vector<T, Abi>, Vector<U, Abi>, Uq, void> {
101  using type = Vc::Vector<fundamental_return_t<T, U>, Abi>;
102 };
103 // 2. Vector × int
104 template <class T, class Abi, class Uq>
105 struct ReturnTypeImpl<Vector<T, Abi>, int, Uq, void> {
106  // conversion from int is always allowed (because its the default when you hardcode a
107  // number)
108  using type = Vc::Vector<T, Abi>;
109 };
110 // 3. Vector × unsigned
111 template <class T, class Abi, class Uq>
112 struct ReturnTypeImpl<Vector<T, Abi>, uint, Uq, void> {
113  // conversion from unsigned int is allowed for all integral Vector<T>, but ensures
114  // unsigned result
115  using type = Vc::Vector<
116  typename std::conditional<std::is_integral<T>::value, std::make_unsigned<T>,
117  std::enable_if<true, T>>::type::type,
118  Abi>;
119 };
120 // 4. Vector × {enum, arithmetic}
121 template <class T, class U, class Abi, class Uq>
122 struct ReturnTypeImpl<
123  Vector<T, Abi>, U, Uq,
124  enable_if<!std::is_class<U>::value && !std::is_same<U, int>::value &&
125  !std::is_same<U, uint>::value &&
126  Traits::is_valid_vector_argument<fundamental_return_t<T, U>>::value,
127  void>> {
128  using type = Vc::Vector<fundamental_return_t<T, U>, Abi>;
129 };
130 // 5. Vector × UDT
131 template <class T, class U, class Abi, class Uq>
132 struct ReturnTypeImpl<
133  Vector<T, Abi>, U, Uq,
134  enable_if<std::is_class<U>::value && !Traits::is_simd_vector<U>::value &&
135  Traits::is_valid_vector_argument<decltype(
136  is_convertible_to_any_vector<T, Abi>(std::declval<Uq>()))>::value,
137  void>> {
138  using type =
140  std::declval<Uq>()))>,
141  Abi>;
142 };
143 template <class V, class Tq, class T = remove_cvref_t<Tq>>
144 using ReturnType = typename ReturnTypeImpl<V, T, Tq>::type;
145 
146 template <class T> struct is_a_type : public std::true_type {
147 };
148 
149 #ifdef Vc_ENABLE_FLOAT_BIT_OPERATORS
150 #define Vc_TEST_FOR_BUILTIN_OPERATOR(op_) true
151 #else
152 #define Vc_TEST_FOR_BUILTIN_OPERATOR(op_) \
153  Detail::is_a_type<decltype(std::declval<typename R::value_type>() \
154  op_ std::declval<typename R::value_type>())>::value
155 #endif
156 } // namespace Detail
157 
158 #define Vc_GENERIC_OPERATOR(op_) \
159  template <class T, class Abi, class U, \
160  class R = Detail::ReturnType<Vector<T, Abi>, U>> \
161  Vc_ALWAYS_INLINE enable_if<Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
162  std::is_convertible<Vector<T, Abi>, R>::value && \
163  std::is_convertible<U, R>::value, \
164  R> \
165  operator op_(Vector<T, Abi> x, U &&y) \
166  { \
167  return Detail::operator op_(R(x), R(std::forward<U>(y))); \
168  } \
169  template <class T, class Abi, class U, \
170  class R = Detail::ReturnType<Vector<T, Abi>, U>> \
171  Vc_ALWAYS_INLINE enable_if<Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
172  !Traits::is_simd_vector<U>::value && \
173  std::is_convertible<Vector<T, Abi>, R>::value && \
174  std::is_convertible<U, R>::value, \
175  R> \
176  operator op_(U &&x, Vector<T, Abi> y) \
177  { \
178  return Detail::operator op_(R(std::forward<U>(x)), R(y)); \
179  } \
180  template <class T, class Abi, class U, \
181  class R = Detail::ReturnType<Vector<T, Abi>, U>> \
182  Vc_ALWAYS_INLINE enable_if<Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
183  std::is_convertible<Vector<T, Abi>, R>::value && \
184  std::is_convertible<U, R>::value, \
185  Vector<T, Abi> &> \
186  operator op_##=(Vector<T, Abi> &x, U &&y) \
187  { \
188  x = Detail::operator op_(R(x), R(std::forward<U>(y))); \
189  return x; \
190  }
191 
192 #define Vc_LOGICAL_OPERATOR(op_) \
193  template <class T, class Abi> \
194  Vc_ALWAYS_INLINE typename Vector<T, Abi>::Mask operator op_(Vector<T, Abi> x, \
195  Vector<T, Abi> y) \
196  { \
197  return !!x op_ !!y; \
198  } \
199  template <class T, class Abi, class U> \
200  Vc_ALWAYS_INLINE \
201  enable_if<std::is_convertible<Vector<T, Abi>, Vector<U, Abi>>::value && \
202  std::is_convertible<Vector<U, Abi>, Vector<T, Abi>>::value, \
203  typename Detail::ReturnType<Vector<T, Abi>, Vector<U, Abi>>::Mask> \
204  operator op_(Vector<T, Abi> x, Vector<U, Abi> y) \
205  { \
206  return !!x op_ !!y; \
207  } \
208  template <class T, class Abi, class U> \
209  Vc_ALWAYS_INLINE enable_if<std::is_same<bool, decltype(!std::declval<U>())>::value, \
210  typename Vector<T, Abi>::Mask> \
211  operator op_(Vector<T, Abi> x, U &&y) \
212  { \
213  using M = typename Vector<T, Abi>::Mask; \
214  return !!x op_ M(!!std::forward<U>(y)); \
215  } \
216  template <class T, class Abi, class U> \
217  Vc_ALWAYS_INLINE enable_if<std::is_same<bool, decltype(!std::declval<U>())>::value, \
218  typename Vector<T, Abi>::Mask> \
219  operator op_(U &&x, Vector<T, Abi> y) \
220  { \
221  using M = typename Vector<T, Abi>::Mask; \
222  return M(!!std::forward<U>(x)) op_ !!y; \
223  }
224 
225 #define Vc_COMPARE_OPERATOR(op_) \
226  template <class T, class Abi, class U, \
227  class R = Detail::ReturnType<Vector<T, Abi>, U>> \
228  Vc_ALWAYS_INLINE enable_if<std::is_convertible<Vector<T, Abi>, R>::value && \
229  std::is_convertible<U, R>::value, \
230  typename R::Mask> \
231  operator op_(Vector<T, Abi> x, U &&y) \
232  { \
233  return Detail::operator op_(R(x), R(std::forward<U>(y))); \
234  } \
235  template <class T, class Abi, class U, \
236  class R = Detail::ReturnType<Vector<T, Abi>, U>> \
237  Vc_ALWAYS_INLINE \
238  enable_if<!Traits::is_simd_vector_internal<remove_cvref_t<U>>::value && \
239  std::is_convertible<Vector<T, Abi>, R>::value && \
240  std::is_convertible<U, R>::value, \
241  typename R::Mask> \
242  operator op_(U &&x, Vector<T, Abi> y) \
243  { \
244  return Detail::operator op_(R(std::forward<U>(x)), R(y)); \
245  }
246 
247 Vc_ALL_LOGICAL (Vc_LOGICAL_OPERATOR);
248 Vc_ALL_BINARY (Vc_GENERIC_OPERATOR);
249 Vc_ALL_ARITHMETICS(Vc_GENERIC_OPERATOR);
250 Vc_ALL_COMPARES (Vc_COMPARE_OPERATOR);
251 
252 #undef Vc_LOGICAL_OPERATOR
253 #undef Vc_GENERIC_OPERATOR
254 #undef Vc_COMPARE_OPERATOR
255 #undef Vc_INVALID_OPERATOR
256 
257 } // namespace Vc
258 #endif // COMMON_OPERATORS_H_
Vc::Vector
Definition: fwddecl.h:53
Vc::uint
unsigned int uint
unsigned int shorthand
Definition: types.h:56