DUNE PDELab (2.8)

debugalign.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_DEBUGALIGN_HH
4#define DUNE_DEBUGALIGN_HH
5
6#include <algorithm>
7#include <cassert>
8#include <cmath>
9#include <complex>
10#include <cstddef>
11#include <cstdint>
12#include <cstdlib> // abs
13#include <functional>
14#include <istream>
15#include <ostream>
16#include <type_traits>
17#include <utility>
18
20#include <dune/common/indices.hh>
24
25namespace Dune {
26
29 std::function<void(const char*, std::size_t, const void*)>;
30
32
39
41
50 void violatedAlignment(const char *className, std::size_t expectedAlignment,
51 const void *address);
52
54 inline bool isAligned(const void *p, std::size_t align)
55 {
56 // a more portable way to do this would be to abuse std::align(), but that
57 // isn't supported by g++-4.9 yet
58 return std::uintptr_t(p) % align == 0;
59 }
60
62 template<std::size_t align, class Impl>
63 class alignas(align) AlignedBase
64 {
65 void checkAlignment() const
66 {
67 auto pimpl = static_cast<const Impl*>(this);
68 if(!isAligned(pimpl, align))
69 violatedAlignment(className<Impl>().c_str(), align, pimpl);
70 }
71 public:
72 AlignedBase() { checkAlignment(); }
73 AlignedBase(const AlignedBase &) { checkAlignment(); }
74 AlignedBase(AlignedBase &&) { checkAlignment(); }
75 ~AlignedBase() { checkAlignment(); }
76
77 AlignedBase& operator=(const AlignedBase &) = default;
78 AlignedBase& operator=(AlignedBase &&) = default;
79 };
80
82 static constexpr auto debugAlignment = 2*alignof(std::max_align_t);
83
84 namespace AlignedNumberImpl {
85
86 template<class T, std::size_t align = debugAlignment>
87 class AlignedNumber;
88
89 } // namespace AlignedNumberImpl
90
91 using AlignedNumberImpl::AlignedNumber;
92
94 template<std::size_t align = debugAlignment, class T>
95 AlignedNumber<T, align> aligned(T value) { return { std::move(value) }; }
96
97 // The purpose of this namespace is to move the `<cmath>` function overloads
98 // out of namespace `Dune`. This avoids problems where people called
99 // e.g. `sqrt(1.0)` inside the `Dune` namespace, without first doing `using
100 // std::sqrt;`. Without any `Dune::sqrt()`, such a use will find
101 // `::sqrt()`, but with `Dune::sqrt()` it will find only `Dune::sqrt()`,
102 // which does not have an overload for `double`.
103 namespace AlignedNumberImpl {
104
106 template<class T, std::size_t align>
108 : public AlignedBase<align, AlignedNumber<T, align> >
109 {
110 T value_;
111
112 public:
113 AlignedNumber() = default;
114 AlignedNumber(T value) : value_(std::move(value)) {}
115 template<class U, std::size_t uAlign,
116 class = std::enable_if_t<(align >= uAlign) &&
117 std::is_convertible<U, T>::value> >
118 AlignedNumber(const AlignedNumber<U, uAlign> &o) : value_(U(o)) {}
119
120 // accessors
121 template<class U,
122 class = std::enable_if_t<std::is_convertible<T, U>::value> >
123 explicit operator U() const { return value_; }
124
125 const T &value() const { return value_; }
126 T &value() { return value_; }
127
128 // I/O
129 template<class charT, class Traits>
130 friend std::basic_istream<charT, Traits>&
131 operator>>(std::basic_istream<charT, Traits>& str, AlignedNumber &u)
132 {
133 return str >> u.value_;
134 }
135
136 template<class charT, class Traits>
137 friend std::basic_ostream<charT, Traits>&
138 operator<<(std::basic_ostream<charT, Traits>& str,
139 const AlignedNumber &u)
140 {
141 return str << u.value_;
142 }
143
144 // The trick with `template<class U = T, class = std::void_t<expr(U)> >` is
145 // needed because at least g++-4.9 seems to evaluates a default argument
146 // in `template<class = std::void_t<expr(T))> >` as soon as possible and will
147 // error out if `expr(T)` is invalid. E.g. for `expr(T)` =
148 // `decltype(--std::declval<T&>())`, instantiating `AlignedNumber<bool>`
149 // will result in an unrecoverable error (`--` cannot be applied to a
150 // `bool`).
151
152 // Increment, decrement
153 template<class U = T, class = std::void_t<decltype(++std::declval<U&>())> >
154 AlignedNumber &operator++() { ++value_; return *this; }
155
156 template<class U = T, class = std::void_t<decltype(--std::declval<U&>())> >
157 AlignedNumber &operator--() { --value_; return *this; }
158
159 template<class U = T, class = std::void_t<decltype(std::declval<U&>()++)> >
160 decltype(auto) operator++(int) { return aligned<align>(value_++); }
161
162 template<class U = T, class = std::void_t<decltype(std::declval<U&>()--)> >
163 decltype(auto) operator--(int) { return aligned<align>(value_--); }
164
165 // unary operators
166 template<class U = T,
167 class = std::void_t<decltype(+std::declval<const U&>())> >
168 decltype(auto) operator+() const { return aligned<align>(+value_); }
169
170 template<class U = T,
171 class = std::void_t<decltype(-std::declval<const U&>())> >
172 decltype(auto) operator-() const { return aligned<align>(-value_); }
173
174 /*
175 * silence warnings from GCC about using `~` on a bool
176 * (when instantiated for T=bool)
177 */
178#if __GNUC__ >= 7
179# pragma GCC diagnostic push
180# pragma GCC diagnostic ignored "-Wbool-operation"
181#endif
182 template<class U = T,
183 class = std::void_t<decltype(~std::declval<const U&>())> >
184 decltype(auto) operator~() const { return aligned<align>(~value_); }
185#if __GNUC__ >= 7
186# pragma GCC diagnostic pop
187#endif
188
189 template<class U = T,
190 class = std::void_t<decltype(!std::declval<const U&>())> >
191 decltype(auto) operator!() const { return aligned<align>(!value_); }
192
193 // assignment operators
194#define DUNE_ASSIGN_OP(OP) \
195 template<class U, std::size_t uAlign, \
196 class = std::enable_if_t< \
197 ( uAlign <= align && \
198 sizeof(std::declval<T&>() OP std::declval<U>()) ) \
199 > > \
200 AlignedNumber &operator OP(const AlignedNumber<U, uAlign> &u) \
201 { \
202 value_ OP U(u); \
203 return *this; \
204 } \
205 \
206 template<class U, \
207 class = std::void_t<decltype(std::declval<T&>() OP \
208 std::declval<U>())> > \
209 AlignedNumber &operator OP(const U &u) \
210 { \
211 value_ OP u; \
212 return *this; \
213 } \
214 \
215 static_assert(true, "Require semicolon to unconfuse editors")
216
217 DUNE_ASSIGN_OP(+=);
218 DUNE_ASSIGN_OP(-=);
219
220 DUNE_ASSIGN_OP(*=);
221 DUNE_ASSIGN_OP(/=);
222 DUNE_ASSIGN_OP(%=);
223
224 DUNE_ASSIGN_OP(^=);
225 DUNE_ASSIGN_OP(&=);
226 DUNE_ASSIGN_OP(|=);
227
228 DUNE_ASSIGN_OP(<<=);
229 DUNE_ASSIGN_OP(>>=);
230
231#undef DUNE_ASSIGN_OP
232 };
233
234 // binary operators
235#define DUNE_BINARY_OP(OP) \
236 template<class T, std::size_t tAlign, class U, std::size_t uAlign, \
237 class = std::void_t<decltype(std::declval<T>() \
238 OP std::declval<U>())> > \
239 decltype(auto) \
240 operator OP(const AlignedNumber<T, tAlign> &t, \
241 const AlignedNumber<U, uAlign> &u) \
242 { \
243 /* can't use std::max(); not constexpr */ \
244 return aligned<(tAlign > uAlign ? tAlign : uAlign)>(T(t) OP U(u)); \
245 } \
246 \
247 template<class T, class U, std::size_t uAlign, \
248 class = std::void_t<decltype(std::declval<T>() \
249 OP std::declval<U>())> > \
250 decltype(auto) \
251 operator OP(const T &t, const AlignedNumber<U, uAlign> &u) \
252 { \
253 return aligned<uAlign>(t OP U(u)); \
254 } \
255 \
256 template<class T, std::size_t tAlign, class U, \
257 class = std::void_t<decltype(std::declval<T>() \
258 OP std::declval<U>())> > \
259 decltype(auto) \
260 operator OP(const AlignedNumber<T, tAlign> &t, const U &u) \
261 { \
262 return aligned<tAlign>(T(t) OP u); \
263 } \
264 \
265 static_assert(true, "Require semicolon to unconfuse editors")
266
267 DUNE_BINARY_OP(+);
268 DUNE_BINARY_OP(-);
269
270 DUNE_BINARY_OP(*);
271 DUNE_BINARY_OP(/);
272 DUNE_BINARY_OP(%);
273
274 DUNE_BINARY_OP(^);
275 DUNE_BINARY_OP(&);
276 DUNE_BINARY_OP(|);
277
278 DUNE_BINARY_OP(<<);
279 DUNE_BINARY_OP(>>);
280
281 DUNE_BINARY_OP(==);
282 DUNE_BINARY_OP(!=);
283 DUNE_BINARY_OP(<);
284 DUNE_BINARY_OP(>);
285 DUNE_BINARY_OP(<=);
286 DUNE_BINARY_OP(>=);
287
288 DUNE_BINARY_OP(&&);
289 DUNE_BINARY_OP(||);
290
291#undef DUNE_BINARY_OP
292
294 //
295 // Overloads for the functions provided by the standard library
296 //
297#define DUNE_UNARY_FUNC(name) \
298 template<class T, std::size_t align> \
299 decltype(auto) name(const AlignedNumber<T, align> &u) \
300 { \
301 using std::name; \
302 return aligned<align>(name(T(u))); \
303 } \
304 static_assert(true, "Require semicolon to unconfuse editors")
305
306 //
307 // <cmath> functions
308 //
309
310 // note: only unary functions are provided at the moment. Getting all the
311 // overloads right for functions with more than one argument is tricky.
312 // All <cmath> functions appear in the list below in the order they are
313 // listed in in the standard, but the unimplemented ones are commented
314 // out.
315
316 // note: abs is provided by both <cstdlib> (for integer) and <cmath> (for
317 // floating point). This overload works for both.
318 DUNE_UNARY_FUNC(abs);
319 DUNE_UNARY_FUNC(acos);
320 DUNE_UNARY_FUNC(acosh);
321 DUNE_UNARY_FUNC(asin);
322 DUNE_UNARY_FUNC(asinh);
323 DUNE_UNARY_FUNC(atan);
324 // atan2
325 DUNE_UNARY_FUNC(atanh);
326 DUNE_UNARY_FUNC(cbrt);
327 DUNE_UNARY_FUNC(ceil);
328 // copysign
329 DUNE_UNARY_FUNC(cos);
330 DUNE_UNARY_FUNC(cosh);
331 DUNE_UNARY_FUNC(erf);
332 DUNE_UNARY_FUNC(erfc);
333 DUNE_UNARY_FUNC(exp);
334 DUNE_UNARY_FUNC(exp2);
335 DUNE_UNARY_FUNC(expm1);
336 DUNE_UNARY_FUNC(fabs);
337 // fdim
338 DUNE_UNARY_FUNC(floor);
339 // fma
340 // fmax
341 // fmin
342 // fmod
343 // frexp
344 // hypos
345 DUNE_UNARY_FUNC(ilogb);
346 // ldexp
347 DUNE_UNARY_FUNC(lgamma);
348 DUNE_UNARY_FUNC(llrint);
349 DUNE_UNARY_FUNC(llround);
350 DUNE_UNARY_FUNC(log);
351 DUNE_UNARY_FUNC(log10);
352 DUNE_UNARY_FUNC(log1p);
353 DUNE_UNARY_FUNC(log2);
354 DUNE_UNARY_FUNC(logb);
355 DUNE_UNARY_FUNC(lrint);
356 DUNE_UNARY_FUNC(lround);
357 // modf
358 DUNE_UNARY_FUNC(nearbyint);
359 // nextafter
360 // nexttoward
361 // pow
362 // remainder
363 // remquo
364 DUNE_UNARY_FUNC(rint);
365 DUNE_UNARY_FUNC(round);
366 // scalbln
367 // scalbn
368 DUNE_UNARY_FUNC(sin);
369 DUNE_UNARY_FUNC(sinh);
370 DUNE_UNARY_FUNC(sqrt);
371 DUNE_UNARY_FUNC(tan);
372 DUNE_UNARY_FUNC(tanh);
373 DUNE_UNARY_FUNC(tgamma);
374 DUNE_UNARY_FUNC(trunc);
375
376 DUNE_UNARY_FUNC(isfinite);
377 DUNE_UNARY_FUNC(isinf);
378 DUNE_UNARY_FUNC(isnan);
379 DUNE_UNARY_FUNC(isnormal);
380 DUNE_UNARY_FUNC(signbit);
381
382 // isgreater
383 // isgreaterequal
384 // isless
385 // islessequal
386 // islessgreater
387 // isunordered
388
389 //
390 // <complex> functions
391 //
392
393 // not all functions are implemented, and unlike for <cmath>, no
394 // comprehensive list is provided
395 DUNE_UNARY_FUNC(real);
396
397#undef DUNE_UNARY_FUNC
398
399 // We need to overload min() and max() since they require types to be
400 // LessThanComparable, which requires `a<b` to be "convertible to bool".
401 // That wording seems to be a leftover from C++03, and today is probably
402 // equivalent to "implicitly convertible". There is also issue 2114
403 // <https://cplusplus.github.io/LWG/issue2114> in the standard (still open
404 // as of 2018-07-06), which strives to require both "implicitly" and
405 // "contextually" convertible -- plus a few other things.
406 //
407 // We do not want our debug type to automatically decay to the underlying
408 // type, so we do not want to make the conversion non-explicit. So the
409 // only option left is to overload min() and max().
410
411 template<class T, std::size_t align>
412 auto max(const AlignedNumber<T, align> &a,
414 {
415 using std::max;
416 return aligned<align>(max(T(a), T(b)));
417 }
418
419 template<class T, std::size_t align>
420 auto max(const T &a, const AlignedNumber<T, align> &b)
421 {
422 using std::max;
423 return aligned<align>(max(a, T(b)));
424 }
425
426 template<class T, std::size_t align>
427 auto max(const AlignedNumber<T, align> &a, const T &b)
428 {
429 using std::max;
430 return aligned<align>(max(T(a), b));
431 }
432
433 template<class T, std::size_t align>
434 auto min(const AlignedNumber<T, align> &a,
435 const AlignedNumber<T, align> &b)
436 {
437 using std::min;
438 return aligned<align>(min(T(a), T(b)));
439 }
440
441 template<class T, std::size_t align>
442 auto min(const T &a, const AlignedNumber<T, align> &b)
443 {
444 using std::min;
445 return aligned<align>(min(a, T(b)));
446 }
447
448 template<class T, std::size_t align>
449 auto min(const AlignedNumber<T, align> &a, const T &b)
450 {
451 using std::min;
452 return aligned<align>(min(T(a), b));
453 }
454
455 } // namespace AlignedNumberImpl
456
457 // SIMD-like functions from "conditional.hh"
458 template<class T, std::size_t align>
459 AlignedNumber<T, align>
460 cond(const AlignedNumber<bool, align> &b,
461 const AlignedNumber<T, align> &v1, const AlignedNumber<T, align> &v2)
462 {
463 return b ? v1 : v2;
464 }
465
466 // SIMD-like functions from "rangeutilities.hh"
467 template<class T, std::size_t align>
468 T max_value(const AlignedNumber<T, align>& val)
469 {
470 return T(val);
471 }
472
473 template<class T, std::size_t align>
474 T min_value(const AlignedNumber<T, align>& val)
475 {
476 return T(val);
477 }
478
479 template<std::size_t align>
480 bool any_true(const AlignedNumber<bool, align>& val)
481 {
482 return bool(val);
483 }
484
485 template<std::size_t align>
486 bool all_true(const AlignedNumber<bool, align>& val)
487 {
488 return bool(val);
489 }
490
491 // SIMD-like functionality from "simd/interface.hh"
492 namespace Simd {
493 namespace Overloads {
494
495 template<class T, std::size_t align>
496 struct ScalarType<AlignedNumber<T, align> > { using type = T; };
497
498 template<class U, class T, std::size_t align>
499 struct RebindType<U, AlignedNumber<T, align> > {
500 using type = AlignedNumber<U, align>;
501 };
502
503 template<class T, std::size_t align>
504 struct LaneCount<AlignedNumber<T, align> > : index_constant<1> {};
505
506 template<class T, std::size_t align>
507 T& lane(ADLTag<5>, std::size_t l, AlignedNumber<T, align> &v)
508 {
509 assert(l == 0);
510 return v.value();
511 }
512
513 template<class T, std::size_t align>
514 T lane(ADLTag<5>, std::size_t l, const AlignedNumber<T, align> &v)
515 {
516 assert(l == 0);
517 return v.value();
518 }
519
520 template<class T, std::size_t align>
523 const AlignedNumber<T, align> &ifTrue,
524 const AlignedNumber<T, align> &ifFalse)
525 {
526 return mask ? ifTrue : ifFalse;
527 }
528
529 template<std::size_t align>
531 {
532 return bool(mask);
533 }
534
535 } // namespace Overloads
536
537 } // namespace Simd
538
539} // namespace Dune
540
541#endif // DUNE_DEBUGALIGN_HH
Basic definitions for SIMD Implementations.
CRTP base mixin class to check alignment.
Definition: debugalign.hh:64
aligned wrappers for arithmetic types
Definition: debugalign.hh:109
A free function to provide the demangled class name of a given object or type as a string.
Default implementations for SIMD Implementations.
Traits for type conversions and type information.
Stream & operator>>(Stream &stream, std::tuple< Ts... > &t)
Read a std::tuple.
Definition: streamoperators.hh:41
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:28
typename Impl::voider< Types... >::type void_t
Is void for all valid input types. The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:38
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:309
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:405
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:151
auto min(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::min()
Definition: defaults.hh:87
bool anyTrue(ADLTag< 0 >, const Mask &mask)=delete
implements Simd::anyTrue()
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:79
Dune namespace.
Definition: alignedallocator.hh:11
void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address)
called when an alignment violation is detected
Definition: debugalign.cc:37
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:45
static constexpr auto debugAlignment
an alignment large enough to trigger alignment errors
Definition: debugalign.hh:82
T lane(std::size_t l, const T &v)
access a lane of a simd vector (scalar version)
Definition: simd.hh:364
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition: conditional.hh:26
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:95
ViolatedAlignmentHandler & violatedAlignmentHandler()
access the handler called by violatedAlignment()
Definition: debugalign.cc:31
bool isAligned(const void *p, std::size_t align)
check whether an address conforms to the given alignment
Definition: debugalign.hh:54
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:29
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition: base.hh:180
should be derived from a Dune::index_constant
Definition: standard.hh:72
should have a member type type
Definition: standard.hh:65
should have a member type type
Definition: standard.hh:58
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Dec 21, 23:30, 2024)