Dune Core Modules (2.9.1)

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// 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
22#include <dune/common/indices.hh>
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;
80 AlignedBase& operator=(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
93 using AlignedNumberImpl::AlignedNumber;
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
230 DUNE_ASSIGN_OP(+=);
231 DUNE_ASSIGN_OP(-=);
232
233 DUNE_ASSIGN_OP(*=);
234 DUNE_ASSIGN_OP(/=);
235 DUNE_ASSIGN_OP(%=);
236
237 DUNE_ASSIGN_OP(^=);
238 DUNE_ASSIGN_OP(&=);
239 DUNE_ASSIGN_OP(|=);
240
241 DUNE_ASSIGN_OP(<<=);
242 DUNE_ASSIGN_OP(>>=);
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
280 DUNE_BINARY_OP(+);
281 DUNE_BINARY_OP(-);
282
283 DUNE_BINARY_OP(*);
284 DUNE_BINARY_OP(/);
285 DUNE_BINARY_OP(%);
286
287 DUNE_BINARY_OP(^);
288 DUNE_BINARY_OP(&);
289 DUNE_BINARY_OP(|);
290
291 DUNE_BINARY_OP(<<);
292 DUNE_BINARY_OP(>>);
293
294 DUNE_BINARY_OP(==);
295 DUNE_BINARY_OP(!=);
296 DUNE_BINARY_OP(<);
297 DUNE_BINARY_OP(>);
298 DUNE_BINARY_OP(<=);
299 DUNE_BINARY_OP(>=);
300
301 DUNE_BINARY_OP(&&);
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);
332 DUNE_UNARY_FUNC(acos);
333 DUNE_UNARY_FUNC(acosh);
334 DUNE_UNARY_FUNC(asin);
335 DUNE_UNARY_FUNC(asinh);
336 DUNE_UNARY_FUNC(atan);
337 // atan2
338 DUNE_UNARY_FUNC(atanh);
339 DUNE_UNARY_FUNC(cbrt);
340 DUNE_UNARY_FUNC(ceil);
341 // copysign
342 DUNE_UNARY_FUNC(cos);
343 DUNE_UNARY_FUNC(cosh);
344 DUNE_UNARY_FUNC(erf);
345 DUNE_UNARY_FUNC(erfc);
346 DUNE_UNARY_FUNC(exp);
347 DUNE_UNARY_FUNC(exp2);
348 DUNE_UNARY_FUNC(expm1);
349 DUNE_UNARY_FUNC(fabs);
350 // fdim
351 DUNE_UNARY_FUNC(floor);
352 // fma
353 // fmax
354 // fmin
355 // fmod
356 // frexp
357 // hypos
358 DUNE_UNARY_FUNC(ilogb);
359 // ldexp
360 DUNE_UNARY_FUNC(lgamma);
361 DUNE_UNARY_FUNC(llrint);
362 DUNE_UNARY_FUNC(llround);
363 DUNE_UNARY_FUNC(log);
364 DUNE_UNARY_FUNC(log10);
365 DUNE_UNARY_FUNC(log1p);
366 DUNE_UNARY_FUNC(log2);
367 DUNE_UNARY_FUNC(logb);
368 DUNE_UNARY_FUNC(lrint);
369 DUNE_UNARY_FUNC(lround);
370 // modf
371 DUNE_UNARY_FUNC(nearbyint);
372 // nextafter
373 // nexttoward
374 // pow
375 // remainder
376 // remquo
377 DUNE_UNARY_FUNC(rint);
378 DUNE_UNARY_FUNC(round);
379 // scalbln
380 // scalbn
381 DUNE_UNARY_FUNC(sin);
382 DUNE_UNARY_FUNC(sinh);
383 DUNE_UNARY_FUNC(sqrt);
384 DUNE_UNARY_FUNC(tan);
385 DUNE_UNARY_FUNC(tanh);
386 DUNE_UNARY_FUNC(tgamma);
387 DUNE_UNARY_FUNC(trunc);
388
389 DUNE_UNARY_FUNC(isfinite);
390 DUNE_UNARY_FUNC(isinf);
391 DUNE_UNARY_FUNC(isnan);
392 DUNE_UNARY_FUNC(isnormal);
393 DUNE_UNARY_FUNC(signbit);
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
408 DUNE_UNARY_FUNC(real);
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>
425 auto max(const AlignedNumber<T, align> &a,
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>
447 auto min(const AlignedNumber<T, align> &a,
448 const AlignedNumber<T, align> &b)
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>
473 cond(const AlignedNumber<bool, align> &b,
474 const AlignedNumber<T, align> &v1, const AlignedNumber<T, align> &v2)
475 {
476 return b ? v1 : v2;
477 }
478
479 // SIMD-like functions from "rangeutilities.hh"
480 template<class T, std::size_t align>
481 T max_value(const AlignedNumber<T, align>& val)
482 {
483 return T(val);
484 }
485
486 template<class T, std::size_t align>
487 T min_value(const AlignedNumber<T, align>& val)
488 {
489 return T(val);
490 }
491
492 template<std::size_t align>
493 bool any_true(const AlignedNumber<bool, align>& val)
494 {
495 return bool(val);
496 }
497
498 template<std::size_t align>
499 bool all_true(const AlignedNumber<bool, align>& val)
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>
509 struct ScalarType<AlignedNumber<T, align> > { using type = T; };
510
511 template<class U, class T, std::size_t align>
512 struct RebindType<U, AlignedNumber<T, align> > {
513 using type = AlignedNumber<U, 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>
520 T& lane(ADLTag<5>, std::size_t l, AlignedNumber<T, align> &v)
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
Basic definitions for SIMD Implementations.
CRTP base mixin class to check alignment.
Definition: debugalign.hh:66
aligned wrappers for arithmetic types
Definition: debugalign.hh:115
A free function to provide the demangled class name of a given object or type as a string.
Default implementations for SIMD Implementations.
Stream & operator>>(Stream &stream, std::tuple< Ts... > &t)
Read a std::tuple.
Definition: streamoperators.hh:43
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:30
typename Impl::voider< Types... >::type void_t
Is void for all valid input types. The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:40
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:311
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:407
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
auto min(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::min()
Definition: defaults.hh:89
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:81
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
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
T lane(std::size_t l, const T &v)
access a lane of a simd vector (scalar version)
Definition: simd.hh:366
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
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:31
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition: base.hh:182
should be derived from a Dune::index_constant
Definition: standard.hh:74
should have a member type type
Definition: standard.hh:67
should have a member type type
Definition: standard.hh:60
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)