dune-common  2.8.0
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 
19 #include <dune/common/classname.hh>
20 #include <dune/common/indices.hh>
21 #include <dune/common/simd/base.hh>
24 
25 namespace 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) &&
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 
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 
271  DUNE_BINARY_OP(/);
272  DUNE_BINARY_OP(%);
273 
275  DUNE_BINARY_OP(&);
276  DUNE_BINARY_OP(|);
277 
280 
283  DUNE_BINARY_OP(<);
284  DUNE_BINARY_OP(>);
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
349  DUNE_UNARY_FUNC(llround);
357  // modf
358  DUNE_UNARY_FUNC(nearbyint);
359  // nextafter
360  // nexttoward
361  // pow
362  // remainder
363  // remquo
366  // scalbln
367  // scalbn
375 
376  DUNE_UNARY_FUNC(isfinite);
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
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>
413  const AlignedNumber<T, align> &b)
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>
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>
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>
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> > {
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
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::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
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:273
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
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
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:95
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
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
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
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:29
T min_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:474
auto max(const AlignedNumber< T, align > &a, const T &b)
Definition: debugalign.hh:427
auto min(const AlignedNumber< T, align > &a, const T &b)
Definition: debugalign.hh:449
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition: debugalign.hh:530
CRTP base mixin class to check alignment.
Definition: debugalign.hh:64
~AlignedBase()
Definition: debugalign.hh:75
AlignedBase & operator=(AlignedBase &&)=default
AlignedBase & operator=(const AlignedBase &)=default
AlignedBase(AlignedBase &&)
Definition: debugalign.hh:74
AlignedBase(const AlignedBase &)
Definition: debugalign.hh:73
AlignedBase()
Definition: debugalign.hh:72
aligned wrappers for arithmetic types
Definition: debugalign.hh:109
DUNE_ASSIGN_OP * DUNE_ASSIGN_OP(/=);DUNE_ASSIGN_OP(%=
T & value()
Definition: debugalign.hh:126
decltype(auto) operator+() const
Definition: debugalign.hh:168
decltype(auto) operator--(int)
Definition: debugalign.hh:163
decltype(auto) operator++(int)
Definition: debugalign.hh:160
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:191
DUNE_ASSIGN_OP^ DUNE_ASSIGN_OP(&=);DUNE_ASSIGN_OP(|=
AlignedNumber & operator--()
Definition: debugalign.hh:157
const T & value() const
Definition: debugalign.hh:125
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
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