Vc  1.4.1
SIMD Vector Classes for C++
where.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2013-2015 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 VC_COMMON_WHERE_H_
29 #define VC_COMMON_WHERE_H_
30 
31 #include "types.h"
32 #include "macros.h"
33 
34 namespace Vc_VERSIONED_NAMESPACE
35 {
36 
37 namespace WhereImpl
38 {
39 
44  template<typename _Mask, typename _LValue> struct MaskedLValue
45  {
46  typedef _Mask Mask;
47  typedef _LValue LValue;
48 
49  const Mask &mask;
50  LValue &lhs;
51 
52  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
53  constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
54  MaskedLValue(const MaskedLValue &) = delete;
55 #ifndef __cpp_guaranteed_copy_elision
56  constexpr MaskedLValue(MaskedLValue &&) = default;
57 #endif
58 
59  /* It is intentional that the assignment operators return void: When a bool is used for the
60  * mask the code might get skipped completely, thus nothing can be returned. This would be
61  * like requiring an if statement to return a value.
62  */
63  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { conditional_assign<Operator:: Assign>(lhs, mask, std::forward<T>(rhs)); }
64  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { conditional_assign<Operator:: PlusAssign>(lhs, mask, std::forward<T>(rhs)); }
65  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { conditional_assign<Operator:: MinusAssign>(lhs, mask, std::forward<T>(rhs)); }
66  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { conditional_assign<Operator:: MultiplyAssign>(lhs, mask, std::forward<T>(rhs)); }
67  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { conditional_assign<Operator:: DivideAssign>(lhs, mask, std::forward<T>(rhs)); }
68  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { conditional_assign<Operator:: RemainderAssign>(lhs, mask, std::forward<T>(rhs)); }
69  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { conditional_assign<Operator:: XorAssign>(lhs, mask, std::forward<T>(rhs)); }
70  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { conditional_assign<Operator:: AndAssign>(lhs, mask, std::forward<T>(rhs)); }
71  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { conditional_assign<Operator:: OrAssign>(lhs, mask, std::forward<T>(rhs)); }
72  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { conditional_assign<Operator:: LeftShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
73  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { conditional_assign<Operator::RightShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
74  Vc_ALWAYS_INLINE void operator++() { conditional_assign<Operator:: PreIncrement>(lhs, mask); }
75  Vc_ALWAYS_INLINE void operator++(int) { conditional_assign<Operator::PostIncrement>(lhs, mask); }
76  Vc_ALWAYS_INLINE void operator--() { conditional_assign<Operator:: PreDecrement>(lhs, mask); }
77  Vc_ALWAYS_INLINE void operator--(int) { conditional_assign<Operator::PostDecrement>(lhs, mask); }
78 
79  // masked gathers
80  template <class T, class IV, class S>
81  Vc_INTRINSIC void operator=(Common::SubscriptOperation<T, IV, S, true> &&rhs)
82  {
83  lhs.gather(std::move(rhs).gatherArguments(), mask);
84  }
85  template <class T, class IV, class S>
86  void operator+=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
87  template <class T, class IV, class S>
88  void operator-=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
89  template <class T, class IV, class S>
90  void operator*=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
91  template <class T, class IV, class S>
92  void operator/=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
93  template <class T, class IV, class S>
94  void operator%=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
95  template <class T, class IV, class S>
96  void operator^=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
97  template <class T, class IV, class S>
98  void operator&=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
99  template <class T, class IV, class S>
100  void operator|=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
101  template <class T, class IV, class S>
102  void operator<<=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
103  template <class T, class IV, class S>
104  void operator>>=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
105  };
106 
107  template <typename _Mask, typename T_, typename I_, typename S_>
108  struct MaskedLValue<_Mask, Common::SubscriptOperation<T_, I_, S_, true>>
109  {
110  typedef _Mask Mask;
111  typedef Common::SubscriptOperation<T_, I_, S_, true> SO;
112 
113  const Mask &mask;
114  SO &lhs;
115 
116  template <typename T> using Decay = typename std::decay<T>::type;
117 
118  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
119  constexpr MaskedLValue(const Mask &m, SO &&l) : mask(m), lhs(l) {}
120  MaskedLValue(const MaskedLValue &) = delete;
121 #ifndef __cpp_guaranteed_copy_elision
122  constexpr MaskedLValue(MaskedLValue &&) = default;
123 #endif
124 
125  /* It is intentional that the assignment operators return void: When a bool is used for the
126  * mask the code might get skipped completely, thus nothing can be returned. This would be
127  * like requiring an if statement to return a value.
128  */
129  template <class T> Vc_ALWAYS_INLINE void operator=(T &&rhs) &&
130  {
131  std::forward<T>(rhs).scatter(std::move(lhs).scatterArguments(), mask);
132  }
133  /*
134  * The following operators maybe make some sense. But only if implemented directly on the
135  * scalar objects in memory. Thus, the user is probably better of with a manual loop.
136  *
137  * If implemented the operators would need to do a masked gather, one operation, and a
138  * masked scatter. There is no way this is going to be efficient.
139  *
140  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) + std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
141  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) - std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
142  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) * std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
143  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) / std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
144  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) % std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
145  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) ^ std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
146  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) & std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
147  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) | std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
148  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) << std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
149  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) >> std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
150  Vc_ALWAYS_INLINE void operator++() { ++lhs(mask); }
151  Vc_ALWAYS_INLINE void operator++(int) { lhs(mask)++; }
152  Vc_ALWAYS_INLINE void operator--() { --lhs(mask); }
153  Vc_ALWAYS_INLINE void operator--(int) { lhs(mask)--; }
154  */
155  };
156 
157  template<typename _LValue> struct MaskedLValue<bool, _LValue>
158  {
159  typedef bool Mask;
160  typedef _LValue LValue;
161 
162  const Mask &mask;
163  LValue &lhs;
164 
165  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
166  constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
167  MaskedLValue(const MaskedLValue &) = delete;
168  constexpr MaskedLValue(MaskedLValue &&) = default;
169 
170  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { if (mask) lhs = std::forward<T>(rhs); }
171  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { if (mask) lhs += std::forward<T>(rhs); }
172  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { if (mask) lhs -= std::forward<T>(rhs); }
173  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { if (mask) lhs *= std::forward<T>(rhs); }
174  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { if (mask) lhs /= std::forward<T>(rhs); }
175  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { if (mask) lhs %= std::forward<T>(rhs); }
176  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { if (mask) lhs ^= std::forward<T>(rhs); }
177  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { if (mask) lhs &= std::forward<T>(rhs); }
178  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { if (mask) lhs |= std::forward<T>(rhs); }
179  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { if (mask) lhs <<= std::forward<T>(rhs); }
180  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { if (mask) lhs >>= std::forward<T>(rhs); }
181  Vc_ALWAYS_INLINE void operator++() { if (mask) ++lhs; }
182  Vc_ALWAYS_INLINE void operator++(int) { if (mask) lhs++; }
183  Vc_ALWAYS_INLINE void operator--() { if (mask) --lhs; }
184  Vc_ALWAYS_INLINE void operator--(int) { if (mask) lhs--; }
185  };
186 
187  template<typename _Mask> struct WhereMask
188  {
189  typedef _Mask Mask;
190  const Mask &mask;
191 
192  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
193  constexpr WhereMask(const Mask &m) : mask(m) {}
194  WhereMask(const WhereMask &) = delete;
195 
196  template <typename T, typename I, typename S>
197  constexpr Vc_WARN_UNUSED_RESULT
198  MaskedLValue<Mask, Common::SubscriptOperation<T, I, S, true>>
199  operator|(Common::SubscriptOperation<T, I, S, true> &&lhs) const
200  {
201  static_assert(!std::is_const<T>::value,
202  "masked scatter to constant memory not possible.");
203  return {mask, std::move(lhs)};
204  }
205 
206  template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator|(T &&lhs) const
207  {
208  static_assert(std::is_lvalue_reference<T>::value, "Syntax error: Incorrect use of Vc::where. Maybe operator precedence got you by surprise. Examples of correct usage:\n"
209  " Vc::where(x < 2) | x += 1;\n"
210  " (Vc::where(x < 2) | x)++;\n"
211  " Vc::where(x < 2)(x) += 1;\n"
212  " Vc::where(x < 2)(x)++;\n"
213  );
214  return { mask, lhs };
215  }
216 
217  template <class T,
218  class = decltype(std::declval<T>() = std::declval<const T &>())>
219  constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator()(T &&lhs) const
220  {
221  return operator|(std::forward<T>(lhs));
222  }
223  };
224 } // namespace WhereImpl
225 
265 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> where(const M &mask)
266 {
267  return { mask };
268 }
269 
270 template <class M, class V>
271 constexpr Vc_WARN_UNUSED_RESULT WhereImpl::MaskedLValue<M, V> where(const M &mask,
272  V &value)
273 {
274  return {mask, value};
275 }
276 
277 // `where` overload for masked scatters. It's necessary because SubscriptOperation doesn't
278 // want to become an lvalue.
279 template <class M, class T, class IT, class Scale>
280 constexpr Vc_WARN_UNUSED_RESULT
281  WhereImpl::MaskedLValue<M, Common::SubscriptOperation<T, IT, Scale, true>>
282  where(const M &mask, Common::SubscriptOperation<T, IT, Scale, true> &&value)
283 {
284  return {mask, std::move(value)};
285 }
286 
287 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> _if(const M &m)
288 {
289  return { m };
290 }
291 
292 } // namespace Vc
293 
294 #endif // VC_COMMON_WHERE_H_
result_vector_type< L, R > operator|(L &&lhs, R &&rhs)
Applies | component-wise and concurrently.
Definition: simdarray.h:1722
constexpr WhereImpl::WhereMask< M > where(const M &mask)
Conditional assignment.
Definition: where.h:265