dune-common 2.12-git
Loading...
Searching...
No Matches
valueproxy.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3#ifndef DUNE_COMMON_SIMD_VALUEPROXY_HH
4#define DUNE_COMMON_SIMD_VALUEPROXY_HH
5
13#include <concepts>
14#include <cstddef>
15#include <type_traits>
16#include <utility>
17
19
20namespace Dune {
21 namespace Simd {
22 namespace Impl {
23
25 template<class Proxy, class ValueType>
26 struct NoExtraOperations {};
27
29
83 template<class V,
84 template<class, class> class ExtraOperations = NoExtraOperations>
85 class ValueProxy
86 : public ExtraOperations<ValueProxy<V, ExtraOperations>,
87 typename V::value_type>
88 {
89 static_assert(std::is_same<V, std::decay_t<V> >::value, "Class "
90 "ValueProxy may only be instantiated with unqualified "
91 "types");
92 static_assert(IsIndexable<V&>::value && IsIndexable<const V&>::value,
93 "Class ValueProxy requires a SIMD type with "
94 "operator[]");
95 public:
96 using value_type = typename V::value_type;
97
98 private:
100 "Only arithmetic types are supported");
101 V &vec_;
102 std::size_t idx_;
103
104 value_type get() const { return std::as_const(vec_)[idx_]; }
105 void set(const value_type &x) const { vec_[idx_] = x; }
106
107 public:
108 ValueProxy(std::size_t idx, V &vec)
109 : vec_(vec), idx_(idx)
110 { }
111
112 ValueProxy(const ValueProxy&) = delete;
113 // allow move construction so we can return proxies from functions
114 ValueProxy(ValueProxy&&) = default;
115
116 operator value_type() const { return get(); }
117
118 // assignment operators
119#define DUNE_SIMD_VALUEPROXY_ASSIGNMENT(OP) \
120 template<class T, \
121 class = decltype(std::declval<value_type&>() OP \
122 autoCopy(std::declval<T>()) )> \
123 ValueProxy operator OP(T &&o) && \
124 { \
125 value_type x = get(); \
126 x OP autoCopy(std::forward<T>(o)); \
127 set(x); \
128 return { idx_, vec_ }; \
129 }
141#undef DUNE_SIMD_VALUEPROXY_ASSIGNMENT
142
143 // unary (prefix) operators
144 template<class T = value_type,
146 ValueProxy operator++()
147 {
148 value_type x = get();
149 set(++x);
150 return { idx_, vec_ };
151 }
152 template<class T = value_type,
154 ValueProxy operator--()
155 {
156 value_type x = get();
157 set(--x);
158 return { idx_, vec_ };
159 }
160
161 // postfix operators
162 template<class T = value_type,
164 value_type operator++(int)
165 {
166 value_type x = get();
167 value_type result = x++;
168 set(x);
169 return result;
170 }
171 template<class T = value_type,
173 value_type operator--(int)
174 {
175 value_type x = get();
176 value_type result = x--;
177 set(x);
178 return result;
179 }
180
181 // swap on proxies swaps the proxied vector entries. As such, it
182 // applies to rvalues of proxies too, not just lvalues
183 friend void swap(const ValueProxy &a, const ValueProxy &b) {
184 value_type tmp = a.get();
185 a.set(b.get());
186 b.set(tmp);
187 }
188 friend void swap(value_type &a, const ValueProxy &b) {
189 value_type tmp = std::move(a);
190 a = b.get();
191 b.set(tmp);
192 }
193 friend void swap(const ValueProxy &a, value_type &b) {
194 value_type tmp = a.get();
195 a.set(std::move(b));
196 b = std::move(tmp);
197 }
198
199 // binary operators with the vector type V (or types derived from
200 // it), between proxies, and with arithmetic scalars
201 //
202 // The scalar operand is `value_type`, so the proxy behaves like the
203 // scalar it represents. The vector operand is deduced and
204 // constrained with `std::derived_from`, so neither operand is
205 // converted implicitly; otherwise e.g. `proxy == scalar` would become
206 // ambiguous with the built-in comparison. Libraries
207 // with catch-all operator templates for their own types (e.g. Vc's
208 // `operator@(Vector<T, Abi>, U&&)`) need more specialized overloads
209 // in `ExtraOperations`. The overloads with arithmetic scalars are
210 // needed for libraries whose vectors broadcast from anything that
211 // converts to their scalar type, including this proxy (e.g.
212 // std::experimental::simd): without them, `proxy << c` with a
213 // `char c` would be ambiguous between the built-in operator and the
214 // library's vector-scalar operator.
215#define DUNE_SIMD_VALUEPROXY_BINARY(OP) \
216 template<std::derived_from<V> W> \
217 friend auto operator OP(const W &l, ValueProxy &&r) \
218 -> decltype(l OP std::declval<value_type>()) \
219 { \
220 return l OP r.get(); \
221 } \
222 template<std::derived_from<V> W> \
223 friend auto operator OP(ValueProxy &&l, const W &r) \
224 -> decltype(std::declval<value_type>() OP r) \
225 { \
226 return l.get() OP r; \
227 } \
228 template<class D = void> \
229 friend auto operator OP(ValueProxy &&l, ValueProxy &&r) \
230 -> decltype(std::declval<std::conditional_t<true, value_type, D> >() \
231 OP std::declval<value_type>()) \
232 { \
233 return l.get() OP r.get(); \
234 } \
235 template<class S, \
236 std::enable_if_t<std::is_arithmetic<S>::value, int> = 0> \
237 friend auto operator OP(const S &l, ValueProxy &&r) \
238 -> decltype(l OP std::declval<value_type>()) \
239 { \
240 return l OP r.get(); \
241 } \
242 template<class S, \
243 std::enable_if_t<std::is_arithmetic<S>::value, int> = 0> \
244 friend auto operator OP(ValueProxy &&l, const S &r) \
245 -> decltype(std::declval<value_type>() OP r) \
246 { \
247 return l.get() OP r; \
248 }
249
266#undef DUNE_SIMD_VALUEPROXY_BINARY
267
268#define DUNE_SIMD_VALUEPROXY_ASSIGN(OP) \
269 template<std::derived_from<V> W> \
270 friend auto operator OP(W &l, ValueProxy &&r) \
271 -> decltype(l OP std::declval<value_type>()) \
272 { \
273 return l OP r.get(); \
274 }
275
286#undef DUNE_SIMD_VALUEPROXY_ASSIGN
287 };
288
289 } // namespace Impl
290 } // namespace Simd
291
293 template<class V, template<class, class> class ExtraOperations>
294 struct AutonomousValueType<Simd::Impl::ValueProxy<V, ExtraOperations> > :
295 AutonomousValueType<typename V::value_type> {};
296
297} // namespace Dune
298
299#endif // DUNE_COMMON_SIMD_VALUEPROXY_HH
#define DUNE_SIMD_VALUEPROXY_BINARY(OP)
Definition valueproxy.hh:215
#define DUNE_SIMD_VALUEPROXY_ASSIGNMENT(OP)
Definition valueproxy.hh:119
#define DUNE_SIMD_VALUEPROXY_ASSIGN(OP)
Definition valueproxy.hh:268
Traits for type conversions and type information.
Dune namespace
Definition alignedallocator.hh:13
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition integersequence.hh:22
T as_const(T... args)
T swap(T... args)