dune-common 2.8.0
Loading...
Searching...
No Matches
debugalign.hh
Go to the documentation of this file.
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
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;
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
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) &&
118 AlignedNumber(const AlignedNumber<U, uAlign> &o) : value_(U(o)) {}
119
120 // accessors
121 template<class U,
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>
132 {
133 return str >> u.value_;
134 }
135
136 template<class charT, class Traits>
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,
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,
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,
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
219
221 DUNE_ASSIGN_OP(/=);
222 DUNE_ASSIGN_OP(%=);
223
225 DUNE_ASSIGN_OP(&=);
226 DUNE_ASSIGN_OP(|=);
227
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
269
273
277
280
287
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);
324 // atan2
328 // copysign
337 // fdim
339 // fma
340 // fmax
341 // fmin
342 // fmod
343 // frexp
344 // hypos
346 // ldexp
357 // modf
358 DUNE_UNARY_FUNC(nearbyint);
359 // nextafter
360 // nexttoward
361 // pow
362 // remainder
363 // remquo
366 // scalbln
367 // scalbn
375
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
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,
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>
462 {
463 return b ? v1 : v2;
464 }
465
466 // SIMD-like functions from "rangeutilities.hh"
467 template<class T, std::size_t align>
469 {
470 return T(val);
471 }
472
473 template<class T, std::size_t align>
475 {
476 return T(val);
477 }
478
479 template<std::size_t align>
481 {
482 return bool(val);
483 }
484
485 template<std::size_t align>
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>
497
498 template<class U, class T, std::size_t align>
499 struct RebindType<U, AlignedNumber<T, 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>
508 {
509 assert(l == 0);
510 return v.value();
511 }
512
513 template<class T, std::size_t align>
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
A free function to provide the demangled class name of a given object or type as a string.
#define DUNE_BINARY_OP(OP)
Definition debugalign.hh:235
#define DUNE_UNARY_FUNC(name)
#define DUNE_ASSIGN_OP(OP)
Definition debugalign.hh:194
Basic definitions for SIMD Implementations.
Default implementations for SIMD Implementations.
Traits for type conversions and type information.
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition bigunsignedint.hh:273
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition defaults.hh:151
STL namespace.
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
bool any_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:480
bool all_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:486
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
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
T max_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:468
T min_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:474
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition debugalign.hh:530
T & lane(ADLTag< 5 >, std::size_t l, AlignedNumber< T, align > &v)
Definition debugalign.hh:507
CRTP base mixin class to check alignment.
Definition debugalign.hh:64
~AlignedBase()
Definition debugalign.hh:75
AlignedBase & operator=(AlignedBase &&)=default
AlignedBase(AlignedBase &&)
Definition debugalign.hh:74
AlignedBase & operator=(const AlignedBase &)=default
AlignedBase(const AlignedBase &)
Definition debugalign.hh:73
AlignedBase()
Definition debugalign.hh:72
aligned wrappers for arithmetic types
Definition debugalign.hh:109
decltype(auto) operator+() const
Definition debugalign.hh:168
decltype(auto) operator--(int)
Definition debugalign.hh:163
DUNE_ASSIGN_OP * DUNE_ASSIGN_OP(/=);DUNE_ASSIGN_OP(%=
decltype(auto) operator++(int)
Definition debugalign.hh:160
decltype(auto) operator!() const
Definition debugalign.hh:191
T & value()
Definition debugalign.hh:126
const T & value() const
Definition debugalign.hh:125
DUNE_ASSIGN_OP^ DUNE_ASSIGN_OP(&=);DUNE_ASSIGN_OP(|=
friend std::basic_istream< charT, Traits > & operator>>(std::basic_istream< charT, Traits > &str, AlignedNumber &u)
Definition debugalign.hh:131
decltype(auto) operator~() const
Definition debugalign.hh:184
AlignedNumber(T value)
Definition debugalign.hh:114
AlignedNumber(const AlignedNumber< U, uAlign > &o)
Definition debugalign.hh:118
decltype(auto) operator-() const
Definition debugalign.hh:172
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition base.hh:180
should have a member type type
Definition standard.hh:58
should have a member type type
Definition standard.hh:65
should be derived from a Dune::index_constant
Definition standard.hh:72
T max(T... args)
T min(T... args)