Vc  1.1.0
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 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the names of contributing organizations nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 }}}*/
28 
29 #ifndef VC_COMMON_WHERE_H_
30 #define VC_COMMON_WHERE_H_
31 
32 #include "types.h"
33 #include "macros.h"
34 
35 namespace Vc_VERSIONED_NAMESPACE
36 {
37 
38 namespace WhereImpl
39 {
40 
45  template<typename _Mask, typename _LValue> struct MaskedLValue
46  {
47  typedef _Mask Mask;
48  typedef _LValue LValue;
49 
50  const Mask &mask;
51  LValue &lhs;
52 
53  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
54  constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
55  MaskedLValue(const MaskedLValue &) = delete;
56  constexpr MaskedLValue(MaskedLValue &&) = default;
57 
58  /* It is intentional that the assignment operators return void: When a bool is used for the
59  * mask the code might get skipped completely, thus nothing can be returned. This would be
60  * like requiring an if statement to return a value.
61  */
62  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { conditional_assign<Operator:: Assign>(lhs, mask, std::forward<T>(rhs)); }
63  template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { conditional_assign<Operator:: PlusAssign>(lhs, mask, std::forward<T>(rhs)); }
64  template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { conditional_assign<Operator:: MinusAssign>(lhs, mask, std::forward<T>(rhs)); }
65  template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { conditional_assign<Operator:: MultiplyAssign>(lhs, mask, std::forward<T>(rhs)); }
66  template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { conditional_assign<Operator:: DivideAssign>(lhs, mask, std::forward<T>(rhs)); }
67  template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { conditional_assign<Operator:: RemainderAssign>(lhs, mask, std::forward<T>(rhs)); }
68  template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { conditional_assign<Operator:: XorAssign>(lhs, mask, std::forward<T>(rhs)); }
69  template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { conditional_assign<Operator:: AndAssign>(lhs, mask, std::forward<T>(rhs)); }
70  template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { conditional_assign<Operator:: OrAssign>(lhs, mask, std::forward<T>(rhs)); }
71  template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { conditional_assign<Operator:: LeftShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
72  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { conditional_assign<Operator::RightShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
73  Vc_ALWAYS_INLINE void operator++() { conditional_assign<Operator:: PreIncrement>(lhs, mask); }
74  Vc_ALWAYS_INLINE void operator++(int) { conditional_assign<Operator::PostIncrement>(lhs, mask); }
75  Vc_ALWAYS_INLINE void operator--() { conditional_assign<Operator:: PreDecrement>(lhs, mask); }
76  Vc_ALWAYS_INLINE void operator--(int) { conditional_assign<Operator::PostDecrement>(lhs, mask); }
77  };
78 
79  template <typename _Mask, typename T_, typename I_, typename S_>
80  struct MaskedLValue<_Mask, Common::SubscriptOperation<T_, I_, S_, true>>
81  {
82  typedef _Mask Mask;
83  typedef Common::SubscriptOperation<T_, I_, S_, true> SO;
84 
85  const Mask &mask;
86  const SO lhs;
87 
88  template <typename T> using Decay = typename std::decay<T>::type;
89 
90  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
91  constexpr MaskedLValue(const Mask &m, SO &&l) : mask(m), lhs(l) {}
92  MaskedLValue(const MaskedLValue &) = delete;
93  constexpr MaskedLValue(MaskedLValue &&) = default;
94 
95  /* It is intentional that the assignment operators return void: When a bool is used for the
96  * mask the code might get skipped completely, thus nothing can be returned. This would be
97  * like requiring an if statement to return a value.
98  */
99  template<typename T> Vc_ALWAYS_INLINE void operator =(T &&rhs) { std::forward<T>(rhs).scatter(lhs.scatterArguments(), mask); }
100  /*
101  * The following operators maybe make some sense. But only if implemented directly on the
102  * scalar objects in memory. Thus, the user is probably better of with a manual loop.
103  *
104  * If implemented the operators would need to do a masked gather, one operation, and a
105  * masked scatter. There is no way this is going to be efficient.
106  *
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  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) >> std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
117  Vc_ALWAYS_INLINE void operator++() { ++lhs(mask); }
118  Vc_ALWAYS_INLINE void operator++(int) { lhs(mask)++; }
119  Vc_ALWAYS_INLINE void operator--() { --lhs(mask); }
120  Vc_ALWAYS_INLINE void operator--(int) { lhs(mask)--; }
121  */
122  };
123 
124  template<typename _LValue> struct MaskedLValue<bool, _LValue>
125  {
126  typedef bool Mask;
127  typedef _LValue LValue;
128 
129  const Mask &mask;
130  LValue &lhs;
131 
132  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
133  constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
134  MaskedLValue(const MaskedLValue &) = delete;
135  constexpr MaskedLValue(MaskedLValue &&) = default;
136 
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  template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { if (mask) lhs >>= std::forward<T>(rhs); }
148  Vc_ALWAYS_INLINE void operator++() { if (mask) ++lhs; }
149  Vc_ALWAYS_INLINE void operator++(int) { if (mask) lhs++; }
150  Vc_ALWAYS_INLINE void operator--() { if (mask) --lhs; }
151  Vc_ALWAYS_INLINE void operator--(int) { if (mask) lhs--; }
152  };
153 
154  template<typename _Mask> struct WhereMask
155  {
156  typedef _Mask Mask;
157  const Mask &mask;
158 
159  // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
160  constexpr WhereMask(const Mask &m) : mask(m) {}
161  WhereMask(const WhereMask &) = delete;
162 
163  template <typename T, typename I, typename S>
164  constexpr Vc_WARN_UNUSED_RESULT
165  MaskedLValue<Mask, Common::SubscriptOperation<T, I, S, true>>
166  operator|(Common::SubscriptOperation<T, I, S, true> &&lhs) const
167  {
168  static_assert(!std::is_const<T>::value,
169  "masked scatter to constant memory not possible.");
170  return {mask, std::move(lhs)};
171  }
172 
173  template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator|(T &&lhs) const
174  {
175  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"
176  " Vc::where(x < 2) | x += 1;\n"
177  " (Vc::where(x < 2) | x)++;\n"
178  " Vc::where(x < 2)(x) += 1;\n"
179  " Vc::where(x < 2)(x)++;\n"
180  );
181  return { mask, lhs };
182  }
183 
184  template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator()(T &&lhs) const
185  {
186  return operator|(std::forward<T>(lhs));
187  }
188  };
189 } // namespace WhereImpl
190 
230 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> where(const M &mask)
231 {
232  return { mask };
233 }
234 
235 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> _if(const M &m)
236 {
237  return { m };
238 }
239 
240 } // namespace Vc
241 
242 #endif // VC_COMMON_WHERE_H_
constexpr WhereImpl::WhereMask< M > where(const M &mask)
Conditional assignment.
Definition: where.h:230