Vc  1.3.2-dev
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  constexpr MaskedLValue(MaskedLValue &&) = default;
56 
57  /* It is intentional that the assignment operators return void: When a bool is used for the
58  * mask the code might get skipped completely, thus nothing can be returned. This would be
59  * like requiring an if statement to return a value.
60  */
61  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { conditional_assign<Operator:: Assign>(lhs, mask, std::forward<T>(rhs)); }
62  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { conditional_assign<Operator:: PlusAssign>(lhs, mask, std::forward<T>(rhs)); }
63  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { conditional_assign<Operator:: MinusAssign>(lhs, mask, std::forward<T>(rhs)); }
64  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { conditional_assign<Operator:: MultiplyAssign>(lhs, mask, std::forward<T>(rhs)); }
65  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { conditional_assign<Operator:: DivideAssign>(lhs, mask, std::forward<T>(rhs)); }
66  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { conditional_assign<Operator:: RemainderAssign>(lhs, mask, std::forward<T>(rhs)); }
67  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { conditional_assign<Operator:: XorAssign>(lhs, mask, std::forward<T>(rhs)); }
68  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { conditional_assign<Operator:: AndAssign>(lhs, mask, std::forward<T>(rhs)); }
69  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { conditional_assign<Operator:: OrAssign>(lhs, mask, std::forward<T>(rhs)); }
70  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { conditional_assign<Operator:: LeftShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
71  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { conditional_assign<Operator::RightShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
72  Vc_ALWAYS_INLINE void operator++() { conditional_assign<Operator:: PreIncrement>(lhs, mask); }
73  Vc_ALWAYS_INLINE void operator++(int) { conditional_assign<Operator::PostIncrement>(lhs, mask); }
74  Vc_ALWAYS_INLINE void operator--() { conditional_assign<Operator:: PreDecrement>(lhs, mask); }
75  Vc_ALWAYS_INLINE void operator--(int) { conditional_assign<Operator::PostDecrement>(lhs, mask); }
76  };
77 
78  template <typename _Mask, typename T_, typename I_, typename S_>
79  struct MaskedLValue<_Mask, Common::SubscriptOperation<T_, I_, S_, true>>
80  {
81  typedef _Mask Mask;
82  typedef Common::SubscriptOperation<T_, I_, S_, true> SO;
83 
84  const Mask &mask;
85  const SO lhs;
86 
87  template <typename T> using Decay = typename std::decay<T>::type;
88 
89  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
90  constexpr MaskedLValue(const Mask &m, SO &&l) : mask(m), lhs(l) {}
91  MaskedLValue(const MaskedLValue &) = delete;
92  constexpr MaskedLValue(MaskedLValue &&) = default;
93 
94  /* It is intentional that the assignment operators return void: When a bool is used for the
95  * mask the code might get skipped completely, thus nothing can be returned. This would be
96  * like requiring an if statement to return a value.
97  */
98  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { std::forward<T>(rhs).scatter(lhs.scatterArguments(), mask); }
99  /*
100  * The following operators maybe make some sense. But only if implemented directly on the
101  * scalar objects in memory. Thus, the user is probably better of with a manual loop.
102  *
103  * If implemented the operators would need to do a masked gather, one operation, and a
104  * masked scatter. There is no way this is going to be efficient.
105  *
106  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) + std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
107  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) - std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
108  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) * std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
109  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) / std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
110  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) % std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
111  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) ^ std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
112  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) & std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
113  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) | std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
114  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) << std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
115  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) >> std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
116  Vc_ALWAYS_INLINE void operator++() { ++lhs(mask); }
117  Vc_ALWAYS_INLINE void operator++(int) { lhs(mask)++; }
118  Vc_ALWAYS_INLINE void operator--() { --lhs(mask); }
119  Vc_ALWAYS_INLINE void operator--(int) { lhs(mask)--; }
120  */
121  };
122 
123  template<typename _LValue> struct MaskedLValue<bool, _LValue>
124  {
125  typedef bool Mask;
126  typedef _LValue LValue;
127 
128  const Mask &mask;
129  LValue &lhs;
130 
131  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
132  constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
133  MaskedLValue(const MaskedLValue &) = delete;
134  constexpr MaskedLValue(MaskedLValue &&) = default;
135 
136  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { if (mask) lhs = std::forward<T>(rhs); }
137  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { if (mask) lhs += std::forward<T>(rhs); }
138  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { if (mask) lhs -= std::forward<T>(rhs); }
139  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { if (mask) lhs *= std::forward<T>(rhs); }
140  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { if (mask) lhs /= std::forward<T>(rhs); }
141  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { if (mask) lhs %= std::forward<T>(rhs); }
142  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { if (mask) lhs ^= std::forward<T>(rhs); }
143  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { if (mask) lhs &= std::forward<T>(rhs); }
144  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { if (mask) lhs |= std::forward<T>(rhs); }
145  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { if (mask) lhs <<= std::forward<T>(rhs); }
146  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { if (mask) lhs >>= std::forward<T>(rhs); }
147  Vc_ALWAYS_INLINE void operator++() { if (mask) ++lhs; }
148  Vc_ALWAYS_INLINE void operator++(int) { if (mask) lhs++; }
149  Vc_ALWAYS_INLINE void operator--() { if (mask) --lhs; }
150  Vc_ALWAYS_INLINE void operator--(int) { if (mask) lhs--; }
151  };
152 
153  template<typename _Mask> struct WhereMask
154  {
155  typedef _Mask Mask;
156  const Mask &mask;
157 
158  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
159  constexpr WhereMask(const Mask &m) : mask(m) {}
160  WhereMask(const WhereMask &) = delete;
161 
162  template <typename T, typename I, typename S>
163  constexpr Vc_WARN_UNUSED_RESULT
164  MaskedLValue<Mask, Common::SubscriptOperation<T, I, S, true>>
165  operator|(Common::SubscriptOperation<T, I, S, true> &&lhs) const
166  {
167  static_assert(!std::is_const<T>::value,
168  "masked scatter to constant memory not possible.");
169  return {mask, std::move(lhs)};
170  }
171 
172  template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator|(T &&lhs) const
173  {
174  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"
175  " Vc::where(x < 2) | x += 1;\n"
176  " (Vc::where(x < 2) | x)++;\n"
177  " Vc::where(x < 2)(x) += 1;\n"
178  " Vc::where(x < 2)(x)++;\n"
179  );
180  return { mask, lhs };
181  }
182 
183  template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator()(T &&lhs) const
184  {
185  return operator|(std::forward<T>(lhs));
186  }
187  };
188 } // namespace WhereImpl
189 
229 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> where(const M &mask)
230 {
231  return { mask };
232 }
233 
234 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> _if(const M &m)
235 {
236  return { m };
237 }
238 
239 } // namespace Vc
240 
241 #endif // VC_COMMON_WHERE_H_
result_vector_type< L, R > operator|(L &&lhs, R &&rhs)
Applies | component-wise and concurrently.
Definition: simdarray.h:1612
constexpr WhereImpl::WhereMask< M > where(const M &mask)
Conditional assignment.
Definition: where.h:229