dune-common 2.9.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// SPDX-FileCopyrightInfo: Copyright (C) DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5#ifndef DUNE_DEBUGALIGN_HH
6#define DUNE_DEBUGALIGN_HH
7
8#include <algorithm>
9#include <cassert>
10#include <cmath>
11#include <complex>
12#include <cstddef>
13#include <cstdint>
14#include <cstdlib> // abs
15#include <functional>
16#include <istream>
17#include <ostream>
18#include <type_traits>
19#include <utility>
20
26
27namespace Dune {
28
31 std::function<void(const char*, std::size_t, const void*)>;
32
34
41
43
52 void violatedAlignment(const char *className, std::size_t expectedAlignment,
53 const void *address);
54
56 inline bool isAligned(const void *p, std::size_t align)
57 {
58 // a more portable way to do this would be to abuse std::align(), but that
59 // isn't supported by g++-4.9 yet
60 return std::uintptr_t(p) % align == 0;
61 }
62
64 template<std::size_t align, class Impl>
65 class alignas(align) AlignedBase
66 {
67 void checkAlignment() const
68 {
69 auto pimpl = static_cast<const Impl*>(this);
70 if(!isAligned(pimpl, align))
71 violatedAlignment(className<Impl>().c_str(), align, pimpl);
72 }
73 public:
74 AlignedBase() { checkAlignment(); }
75 AlignedBase(const AlignedBase &) { checkAlignment(); }
76 AlignedBase(AlignedBase &&) { checkAlignment(); }
77 ~AlignedBase() { checkAlignment(); }
78
79 AlignedBase& operator=(const AlignedBase &) = default;
81 };
82
84 static constexpr auto debugAlignment = 2*alignof(std::max_align_t);
85
86 namespace AlignedNumberImpl {
87
88 template<class T, std::size_t align = debugAlignment>
89 class AlignedNumber;
90
91 } // namespace AlignedNumberImpl
92
94
95 template<class T, std::size_t align>
96 struct IsNumber<AlignedNumberImpl::AlignedNumber<T,align>>
97 : public std::true_type {};
98
100 template<std::size_t align = debugAlignment, class T>
101 AlignedNumber<T, align> aligned(T value) { return { std::move(value) }; }
102
103 // The purpose of this namespace is to move the `<cmath>` function overloads
104 // out of namespace `Dune`. This avoids problems where people called
105 // e.g. `sqrt(1.0)` inside the `Dune` namespace, without first doing `using
106 // std::sqrt;`. Without any `Dune::sqrt()`, such a use will find
107 // `::sqrt()`, but with `Dune::sqrt()` it will find only `Dune::sqrt()`,
108 // which does not have an overload for `double`.
109 namespace AlignedNumberImpl {
110
112 template<class T, std::size_t align>
114 : public AlignedBase<align, AlignedNumber<T, align> >
115 {
116 T value_;
117
118 public:
119 AlignedNumber() = default;
120 AlignedNumber(T value) : value_(std::move(value)) {}
121 template<class U, std::size_t uAlign,
122 class = std::enable_if_t<(align >= uAlign) &&
123 std::is_convertible<U, T>::value> >
124 AlignedNumber(const AlignedNumber<U, uAlign> &o) : value_(U(o)) {}
125
126 // accessors
127 template<class U,
128 class = std::enable_if_t<std::is_convertible<T, U>::value> >
129 explicit operator U() const { return value_; }
130
131 const T &value() const { return value_; }
132 T &value() { return value_; }
133
134 // I/O
135 template<class charT, class Traits>
136 friend std::basic_istream<charT, Traits>&
137 operator>>(std::basic_istream<charT, Traits>& str, AlignedNumber &u)
138 {
139 return str >> u.value_;
140 }
141
142 template<class charT, class Traits>
143 friend std::basic_ostream<charT, Traits>&
144 operator<<(std::basic_ostream<charT, Traits>& str,
145 const AlignedNumber &u)
146 {
147 return str << u.value_;
148 }
149
150 // The trick with `template<class U = T, class = std::void_t<expr(U)> >` is
151 // needed because at least g++-4.9 seems to evaluates a default argument
152 // in `template<class = std::void_t<expr(T))> >` as soon as possible and will
153 // error out if `expr(T)` is invalid. E.g. for `expr(T)` =
154 // `decltype(--std::declval<T&>())`, instantiating `AlignedNumber<bool>`
155 // will result in an unrecoverable error (`--` cannot be applied to a
156 // `bool`).
157
158 // Increment, decrement
159 template<class U = T, class = std::void_t<decltype(++std::declval<U&>())> >
160 AlignedNumber &operator++() { ++value_; return *this; }
161
162 template<class U = T, class = std::void_t<decltype(--std::declval<U&>())> >
163 AlignedNumber &operator--() { --value_; return *this; }
164
165 template<class U = T, class = std::void_t<decltype(std::declval<U&>()++)> >
166 decltype(auto) operator++(int) { return aligned<align>(value_++); }
167
168 template<class U = T, class = std::void_t<decltype(std::declval<U&>()--)> >
169 decltype(auto) operator--(int) { return aligned<align>(value_--); }
170
171 // unary operators
172 template<class U = T,
173 class = std::void_t<decltype(+std::declval<const U&>())> >
174 decltype(auto) operator+() const { return aligned<align>(+value_); }
175
176 template<class U = T,
177 class = std::void_t<decltype(-std::declval<const U&>())> >
178 decltype(auto) operator-() const { return aligned<align>(-value_); }
179
180 /*
181 * silence warnings from GCC about using `~` on a bool
182 * (when instantiated for T=bool)
183 */
184#if __GNUC__ >= 7
185# pragma GCC diagnostic push
186# pragma GCC diagnostic ignored "-Wbool-operation"
187#endif
188#ifdef __clang__
189# pragma clang diagnostic push
190# pragma clang diagnostic ignored "-Wbool-operation"
191#endif
192 template<class U = T,
193 class = std::void_t<decltype(~std::declval<const U&>())> >
194 decltype(auto) operator~() const { return aligned<align>(~value_); }
195#if __GNUC__ >= 7
196# pragma GCC diagnostic pop
197#endif
198#ifdef __clang__
199# pragma clang diagnostic pop
200#endif
201
202 template<class U = T,
203 class = std::void_t<decltype(!std::declval<const U&>())> >
204 decltype(auto) operator!() const { return aligned<align>(!value_); }
205
206 // assignment operators
207#define DUNE_ASSIGN_OP(OP) \
208 template<class U, std::size_t uAlign, \
209 class = std::enable_if_t< \
210 ( uAlign <= align && \
211 sizeof(std::declval<T&>() OP std::declval<U>()) ) \
212 > > \
213 AlignedNumber &operator OP(const AlignedNumber<U, uAlign> &u) \
214 { \
215 value_ OP U(u); \
216 return *this; \
217 } \
218 \
219 template<class U, \
220 class = std::void_t<decltype(std::declval<T&>() OP \
221 std::declval<U>())> > \
222 AlignedNumber &operator OP(const U &u) \
223 { \
224 value_ OP u; \
225 return *this; \
226 } \
227 \
228 static_assert(true, "Require semicolon to unconfuse editors")
229
232
234 DUNE_ASSIGN_OP(/=);
235 DUNE_ASSIGN_OP(%=);
236
238 DUNE_ASSIGN_OP(&=);
239 DUNE_ASSIGN_OP(|=);
240
243
244#undef DUNE_ASSIGN_OP
245 };
246
247 // binary operators
248#define DUNE_BINARY_OP(OP) \
249 template<class T, std::size_t tAlign, class U, std::size_t uAlign, \
250 class = std::void_t<decltype(std::declval<T>() \
251 OP std::declval<U>())> > \
252 decltype(auto) \
253 operator OP(const AlignedNumber<T, tAlign> &t, \
254 const AlignedNumber<U, uAlign> &u) \
255 { \
256 /* can't use std::max(); not constexpr */ \
257 return aligned<(tAlign > uAlign ? tAlign : uAlign)>(T(t) OP U(u)); \
258 } \
259 \
260 template<class T, class U, std::size_t uAlign, \
261 class = std::void_t<decltype(std::declval<T>() \
262 OP std::declval<U>())> > \
263 decltype(auto) \
264 operator OP(const T &t, const AlignedNumber<U, uAlign> &u) \
265 { \
266 return aligned<uAlign>(t OP U(u)); \
267 } \
268 \
269 template<class T, std::size_t tAlign, class U, \
270 class = std::void_t<decltype(std::declval<T>() \
271 OP std::declval<U>())> > \
272 decltype(auto) \
273 operator OP(const AlignedNumber<T, tAlign> &t, const U &u) \
274 { \
275 return aligned<tAlign>(T(t) OP u); \
276 } \
277 \
278 static_assert(true, "Require semicolon to unconfuse editors")
279
282
286
290
293
300
302 DUNE_BINARY_OP(||);
303
304#undef DUNE_BINARY_OP
305
307 //
308 // Overloads for the functions provided by the standard library
309 //
310#define DUNE_UNARY_FUNC(name) \
311 template<class T, std::size_t align> \
312 decltype(auto) name(const AlignedNumber<T, align> &u) \
313 { \
314 using std::name; \
315 return aligned<align>(name(T(u))); \
316 } \
317 static_assert(true, "Require semicolon to unconfuse editors")
318
319 //
320 // <cmath> functions
321 //
322
323 // note: only unary functions are provided at the moment. Getting all the
324 // overloads right for functions with more than one argument is tricky.
325 // All <cmath> functions appear in the list below in the order they are
326 // listed in in the standard, but the unimplemented ones are commented
327 // out.
328
329 // note: abs is provided by both <cstdlib> (for integer) and <cmath> (for
330 // floating point). This overload works for both.
331 DUNE_UNARY_FUNC(abs);
337 // atan2
341 // copysign
350 // fdim
352 // fma
353 // fmax
354 // fmin
355 // fmod
356 // frexp
357 // hypos
359 // ldexp
370 // modf
371 DUNE_UNARY_FUNC(nearbyint);
372 // nextafter
373 // nexttoward
374 // pow
375 // remainder
376 // remquo
379 // scalbln
380 // scalbn
388
394
395 // isgreater
396 // isgreaterequal
397 // isless
398 // islessequal
399 // islessgreater
400 // isunordered
401
402 //
403 // <complex> functions
404 //
405
406 // not all functions are implemented, and unlike for <cmath>, no
407 // comprehensive list is provided
409
410#undef DUNE_UNARY_FUNC
411
412 // We need to overload min() and max() since they require types to be
413 // LessThanComparable, which requires `a<b` to be "convertible to bool".
414 // That wording seems to be a leftover from C++03, and today is probably
415 // equivalent to "implicitly convertible". There is also issue 2114
416 // <https://cplusplus.github.io/LWG/issue2114> in the standard (still open
417 // as of 2018-07-06), which strives to require both "implicitly" and
418 // "contextually" convertible -- plus a few other things.
419 //
420 // We do not want our debug type to automatically decay to the underlying
421 // type, so we do not want to make the conversion non-explicit. So the
422 // only option left is to overload min() and max().
423
424 template<class T, std::size_t align>
427 {
428 using std::max;
429 return aligned<align>(max(T(a), T(b)));
430 }
431
432 template<class T, std::size_t align>
433 auto max(const T &a, const AlignedNumber<T, align> &b)
434 {
435 using std::max;
436 return aligned<align>(max(a, T(b)));
437 }
438
439 template<class T, std::size_t align>
440 auto max(const AlignedNumber<T, align> &a, const T &b)
441 {
442 using std::max;
443 return aligned<align>(max(T(a), b));
444 }
445
446 template<class T, std::size_t align>
449 {
450 using std::min;
451 return aligned<align>(min(T(a), T(b)));
452 }
453
454 template<class T, std::size_t align>
455 auto min(const T &a, const AlignedNumber<T, align> &b)
456 {
457 using std::min;
458 return aligned<align>(min(a, T(b)));
459 }
460
461 template<class T, std::size_t align>
462 auto min(const AlignedNumber<T, align> &a, const T &b)
463 {
464 using std::min;
465 return aligned<align>(min(T(a), b));
466 }
467
468 } // namespace AlignedNumberImpl
469
470 // SIMD-like functions from "conditional.hh"
471 template<class T, std::size_t align>
472 AlignedNumber<T, align>
475 {
476 return b ? v1 : v2;
477 }
478
479 // SIMD-like functions from "rangeutilities.hh"
480 template<class T, std::size_t align>
482 {
483 return T(val);
484 }
485
486 template<class T, std::size_t align>
488 {
489 return T(val);
490 }
491
492 template<std::size_t align>
494 {
495 return bool(val);
496 }
497
498 template<std::size_t align>
500 {
501 return bool(val);
502 }
503
504 // SIMD-like functionality from "simd/interface.hh"
505 namespace Simd {
506 namespace Overloads {
507
508 template<class T, std::size_t align>
510
511 template<class U, class T, std::size_t align>
512 struct RebindType<U, AlignedNumber<T, align> > {
514 };
515
516 template<class T, std::size_t align>
517 struct LaneCount<AlignedNumber<T, align> > : index_constant<1> {};
518
519 template<class T, std::size_t align>
521 {
522 assert(l == 0);
523 return v.value();
524 }
525
526 template<class T, std::size_t align>
527 T lane(ADLTag<5>, std::size_t l, const AlignedNumber<T, align> &v)
528 {
529 assert(l == 0);
530 return v.value();
531 }
532
533 template<class T, std::size_t align>
536 const AlignedNumber<T, align> &ifTrue,
537 const AlignedNumber<T, align> &ifFalse)
538 {
539 return mask ? ifTrue : ifFalse;
540 }
541
542 template<std::size_t align>
544 {
545 return bool(mask);
546 }
547
548 } // namespace Overloads
549
550 } // namespace Simd
551
552} // namespace Dune
553
554#endif // DUNE_DEBUGALIGN_HH
Traits for type conversions and type information.
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:248
#define DUNE_UNARY_FUNC(name)
#define DUNE_ASSIGN_OP(OP)
Definition debugalign.hh:207
Default implementations for SIMD Implementations.
Basic definitions for SIMD Implementations.
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition indices.hh:30
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition bigunsignedint.hh:278
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition defaults.hh:153
STL namespace.
Dune namespace.
Definition alignedallocator.hh:13
void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address)
called when an alignment violation is detected
Definition debugalign.cc:39
bool any_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:493
bool all_true(const AlignedNumber< bool, align > &val)
Definition debugalign.hh:499
std::string className()
Provide the demangled class name of a type T as a string.
Definition classname.hh:47
static constexpr auto debugAlignment
an alignment large enough to trigger alignment errors
Definition debugalign.hh:84
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition conditional.hh:28
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition debugalign.hh:101
ViolatedAlignmentHandler & violatedAlignmentHandler()
access the handler called by violatedAlignment()
Definition debugalign.cc:33
bool isAligned(const void *p, std::size_t align)
check whether an address conforms to the given alignment
Definition debugalign.hh:56
T max_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:481
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition debugalign.hh:31
T min_value(const AlignedNumber< T, align > &val)
Definition debugalign.hh:487
auto min(const AlignedNumber< T, align > &a, const AlignedNumber< T, align > &b)
Definition debugalign.hh:447
auto max(const AlignedNumber< T, align > &a, const AlignedNumber< T, align > &b)
Definition debugalign.hh:425
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition debugalign.hh:543
T & lane(ADLTag< 5 >, std::size_t l, AlignedNumber< T, align > &v)
Definition debugalign.hh:520
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition typetraits.hh:194
CRTP base mixin class to check alignment.
Definition debugalign.hh:66
~AlignedBase()
Definition debugalign.hh:77
AlignedBase & operator=(AlignedBase &&)=default
AlignedBase(AlignedBase &&)
Definition debugalign.hh:76
AlignedBase & operator=(const AlignedBase &)=default
AlignedBase(const AlignedBase &)
Definition debugalign.hh:75
AlignedBase()
Definition debugalign.hh:74
aligned wrappers for arithmetic types
Definition debugalign.hh:115
decltype(auto) operator+() const
Definition debugalign.hh:174
decltype(auto) operator--(int)
Definition debugalign.hh:169
DUNE_ASSIGN_OP * DUNE_ASSIGN_OP(/=);DUNE_ASSIGN_OP(%=
decltype(auto) operator++(int)
Definition debugalign.hh:166
decltype(auto) operator!() const
Definition debugalign.hh:204
T & value()
Definition debugalign.hh:132
const T & value() const
Definition debugalign.hh:131
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:137
decltype(auto) operator~() const
Definition debugalign.hh:194
AlignedNumber(T value)
Definition debugalign.hh:120
AlignedNumber(const AlignedNumber< U, uAlign > &o)
Definition debugalign.hh:124
decltype(auto) operator-() const
Definition debugalign.hh:178
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition base.hh:182
should have a member type type
Definition standard.hh:60
should have a member type type
Definition standard.hh:67
should be derived from a Dune::index_constant
Definition standard.hh:74