Vc 1.4.5
SIMD Vector Classes for C++
 
Loading...
Searching...
No Matches
where.h
1/* This file is part of the Vc library. {{{
2Copyright © 2013-2015 Matthias Kretz <kretz@kde.org>
3
4Redistribution and use in source and binary forms, with or without
5modification, 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
15THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22ON 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
24SOFTWARE, 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
34namespace Vc_VERSIONED_NAMESPACE
35{
36
37namespace 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
265template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> where(const M &mask)
266{
267 return { mask };
268}
269
270template <class M, class V>
271constexpr 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.
279template <class M, class T, class IT, class Scale>
280constexpr 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
287template<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_
constexpr WhereImpl::WhereMask< M > where(const M &mask)
Conditional assignment.
Definition where.h:265