Dune Core Modules (unstable)

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 © 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 
21 #include <dune/common/classname.hh>
22 #include <dune/common/indices.hh>
23 #include <dune/common/simd/base.hh>
26 
27 namespace 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,
426  const AlignedNumber<T, align> &b)
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:29
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
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:506
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
bool anyTrue(ADLTag< 0 >, const Mask &mask)=delete
implements Simd::anyTrue()
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
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:101
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
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.80.0 (May 2, 22:35, 2024)