dune-common  2.11
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 © 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  void* aligned_p = (void*)p;
59  std::size_t space = align*2;
60  return p == std::align(align, align, aligned_p, space);
61  }
62 
64  template<std::size_t align, class Impl>
65  struct alignas(align) AlignedBase
66  {
75  static void* operator new(std::size_t count, void* ptr) {
76  if(!isAligned(ptr, align))
77  violatedAlignment(className<Impl>().c_str(), align, ptr);
78  return ::operator new(count*sizeof(Impl), ptr);
79  }
80 
89  static void* operator new[](std::size_t count, void* ptr) {
90  if(!isAligned(ptr, align))
91  violatedAlignment(className<Impl>().c_str(), align, ptr);
92  return ::operator new[](count*sizeof(Impl), ptr);
93  }
94  };
95 
97  static constexpr auto debugAlignment = 2*alignof(std::max_align_t);
98 
99  namespace AlignedNumberImpl {
100 
101  template<class T, std::size_t align = debugAlignment>
102  class AlignedNumber;
103 
104  } // namespace AlignedNumberImpl
105 
106  using AlignedNumberImpl::AlignedNumber;
107 
108  template<class T, std::size_t align>
109  struct IsNumber<AlignedNumberImpl::AlignedNumber<T,align>>
110  : public std::true_type {};
111 
113  template<std::size_t align = debugAlignment, class T>
114  AlignedNumber<T, align> aligned(T value) { return { std::move(value) }; }
115 
116  // The purpose of this namespace is to move the `<cmath>` function overloads
117  // out of namespace `Dune`. This avoids problems where people called
118  // e.g. `sqrt(1.0)` inside the `Dune` namespace, without first doing `using
119  // std::sqrt;`. Without any `Dune::sqrt()`, such a use will find
120  // `::sqrt()`, but with `Dune::sqrt()` it will find only `Dune::sqrt()`,
121  // which does not have an overload for `double`.
122  namespace AlignedNumberImpl {
123 
125  template<class T, std::size_t align>
126  class AlignedNumber
127  : public AlignedBase<align, AlignedNumber<T, align> >
128  {
129  T value_;
130 
131  public:
132  AlignedNumber() = default;
133  AlignedNumber(T value) : value_(std::move(value)) {}
134  template<class U, std::size_t uAlign,
135  class = std::enable_if_t<(align >= uAlign) &&
136  std::is_convertible<U, T>::value> >
137  AlignedNumber(const AlignedNumber<U, uAlign> &o) : value_(U(o)) {}
138 
139  // accessors
140  template<class U,
141  class = std::enable_if_t<std::is_convertible<T, U>::value> >
142  explicit operator U() const { return value_; }
143 
144  const T &value() const { return value_; }
145  T &value() { return value_; }
146 
147  // I/O
148  template<class charT, class Traits>
149  friend std::basic_istream<charT, Traits>&
150  operator>>(std::basic_istream<charT, Traits>& str, AlignedNumber &u)
151  {
152  return str >> u.value_;
153  }
154 
155  template<class charT, class Traits>
156  friend std::basic_ostream<charT, Traits>&
157  operator<<(std::basic_ostream<charT, Traits>& str,
158  const AlignedNumber &u)
159  {
160  return str << u.value_;
161  }
162 
163  // The trick with `template<class U = T, class = std::void_t<expr(U)> >` is
164  // needed because at least g++-4.9 seems to evaluates a default argument
165  // in `template<class = std::void_t<expr(T))> >` as soon as possible and will
166  // error out if `expr(T)` is invalid. E.g. for `expr(T)` =
167  // `decltype(--std::declval<T&>())`, instantiating `AlignedNumber<bool>`
168  // will result in an unrecoverable error (`--` cannot be applied to a
169  // `bool`).
170 
171  // Increment, decrement
172  template<class U = T, class = std::void_t<decltype(++std::declval<U&>())> >
173  AlignedNumber &operator++() { ++value_; return *this; }
174 
175  template<class U = T, class = std::void_t<decltype(--std::declval<U&>())> >
176  AlignedNumber &operator--() { --value_; return *this; }
177 
178  template<class U = T, class = std::void_t<decltype(std::declval<U&>()++)> >
179  decltype(auto) operator++(int) { return aligned<align>(value_++); }
180 
181  template<class U = T, class = std::void_t<decltype(std::declval<U&>()--)> >
182  decltype(auto) operator--(int) { return aligned<align>(value_--); }
183 
184  // unary operators
185  template<class U = T,
186  class = std::void_t<decltype(+std::declval<const U&>())> >
187  decltype(auto) operator+() const { return aligned<align>(+value_); }
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  /*
194  * silence warnings from GCC about using `~` on a bool
195  * (when instantiated for T=bool)
196  */
197 #if __GNUC__ >= 7
198 # pragma GCC diagnostic push
199 # pragma GCC diagnostic ignored "-Wbool-operation"
200 #endif
201 #ifdef __clang__
202 # pragma clang diagnostic push
203 # pragma clang diagnostic ignored "-Wbool-operation"
204 #endif
205  template<class U = T,
206  class = std::void_t<decltype(~std::declval<const U&>())> >
207  decltype(auto) operator~() const { return aligned<align>(~value_); }
208 #if __GNUC__ >= 7
209 # pragma GCC diagnostic pop
210 #endif
211 #ifdef __clang__
212 # pragma clang diagnostic pop
213 #endif
214 
215  template<class U = T,
216  class = std::void_t<decltype(!std::declval<const U&>())> >
217  decltype(auto) operator!() const { return aligned<align>(!value_); }
218 
219  // assignment operators
220 #define DUNE_ASSIGN_OP(OP) \
221  template<class U, std::size_t uAlign, \
222  class = std::enable_if_t< \
223  ( uAlign <= align && \
224  sizeof(std::declval<T&>() OP std::declval<U>()) ) \
225  > > \
226  AlignedNumber &operator OP(const AlignedNumber<U, uAlign> &u) \
227  { \
228  value_ OP U(u); \
229  return *this; \
230  } \
231  \
232  template<class U, \
233  class = std::void_t<decltype(std::declval<T&>() OP \
234  std::declval<U>())> > \
235  AlignedNumber &operator OP(const U &u) \
236  { \
237  value_ OP u; \
238  return *this; \
239  } \
240  \
241  static_assert(true, "Require semicolon to unconfuse editors")
242 
243  DUNE_ASSIGN_OP(+=);
244  DUNE_ASSIGN_OP(-=);
245 
246  DUNE_ASSIGN_OP(*=);
247  DUNE_ASSIGN_OP(/=);
248  DUNE_ASSIGN_OP(%=);
249 
250  DUNE_ASSIGN_OP(^=);
251  DUNE_ASSIGN_OP(&=);
252  DUNE_ASSIGN_OP(|=);
253 
254  DUNE_ASSIGN_OP(<<=);
255  DUNE_ASSIGN_OP(>>=);
256 
257 #undef DUNE_ASSIGN_OP
258  };
259 
260  // binary operators
261 #define DUNE_BINARY_OP(OP) \
262  template<class T, std::size_t tAlign, class U, std::size_t uAlign, \
263  class = std::void_t<decltype(std::declval<T>() \
264  OP std::declval<U>())> > \
265  decltype(auto) \
266  operator OP(const AlignedNumber<T, tAlign> &t, \
267  const AlignedNumber<U, uAlign> &u) \
268  { \
269  /* can't use std::max(); not constexpr */ \
270  return aligned<(tAlign > uAlign ? tAlign : uAlign)>(T(t) OP U(u)); \
271  } \
272  \
273  template<class T, class U, std::size_t uAlign, \
274  class = std::void_t<decltype(std::declval<T>() \
275  OP std::declval<U>())> > \
276  decltype(auto) \
277  operator OP(const T &t, const AlignedNumber<U, uAlign> &u) \
278  { \
279  return aligned<uAlign>(t OP U(u)); \
280  } \
281  \
282  template<class T, std::size_t tAlign, class U, \
283  class = std::void_t<decltype(std::declval<T>() \
284  OP std::declval<U>())> > \
285  decltype(auto) \
286  operator OP(const AlignedNumber<T, tAlign> &t, const U &u) \
287  { \
288  return aligned<tAlign>(T(t) OP u); \
289  } \
290  \
291  static_assert(true, "Require semicolon to unconfuse editors")
292 
293  DUNE_BINARY_OP(+);
294  DUNE_BINARY_OP(-);
295 
296  DUNE_BINARY_OP(*);
297  DUNE_BINARY_OP(/);
298  DUNE_BINARY_OP(%);
299 
300  DUNE_BINARY_OP(^);
301  DUNE_BINARY_OP(&);
302  DUNE_BINARY_OP(|);
303 
304  DUNE_BINARY_OP(<<);
305  DUNE_BINARY_OP(>>);
306 
307  DUNE_BINARY_OP(==);
308  DUNE_BINARY_OP(!=);
309  DUNE_BINARY_OP(<);
310  DUNE_BINARY_OP(>);
311  DUNE_BINARY_OP(<=);
312  DUNE_BINARY_OP(>=);
313 
314  DUNE_BINARY_OP(&&);
315  DUNE_BINARY_OP(||);
316 
317 #undef DUNE_BINARY_OP
318 
320  //
321  // Overloads for the functions provided by the standard library
322  //
323 #define DUNE_UNARY_FUNC(name) \
324  template<class T, std::size_t align> \
325  decltype(auto) name(const AlignedNumber<T, align> &u) \
326  { \
327  using std::name; \
328  return aligned<align>(name(T(u))); \
329  } \
330  static_assert(true, "Require semicolon to unconfuse editors")
331 
332  //
333  // <cmath> functions
334  //
335 
336  // note: only unary functions are provided at the moment. Getting all the
337  // overloads right for functions with more than one argument is tricky.
338  // All <cmath> functions appear in the list below in the order they are
339  // listed in in the standard, but the unimplemented ones are commented
340  // out.
341 
342  // note: abs is provided by both <cstdlib> (for integer) and <cmath> (for
343  // floating point). This overload works for both.
345  DUNE_UNARY_FUNC(acos);
346  DUNE_UNARY_FUNC(acosh);
347  DUNE_UNARY_FUNC(asin);
348  DUNE_UNARY_FUNC(asinh);
349  DUNE_UNARY_FUNC(atan);
350  // atan2
351  DUNE_UNARY_FUNC(atanh);
352  DUNE_UNARY_FUNC(cbrt);
353  DUNE_UNARY_FUNC(ceil);
354  // copysign
355  DUNE_UNARY_FUNC(cos);
356  DUNE_UNARY_FUNC(cosh);
357  DUNE_UNARY_FUNC(erf);
358  DUNE_UNARY_FUNC(erfc);
359  DUNE_UNARY_FUNC(exp);
360  DUNE_UNARY_FUNC(exp2);
361  DUNE_UNARY_FUNC(expm1);
362  DUNE_UNARY_FUNC(fabs);
363  // fdim
364  DUNE_UNARY_FUNC(floor);
365  // fma
366  // fmax
367  // fmin
368  // fmod
369  // frexp
370  // hypos
371  DUNE_UNARY_FUNC(ilogb);
372  // ldexp
373  DUNE_UNARY_FUNC(lgamma);
374  DUNE_UNARY_FUNC(llrint);
375  DUNE_UNARY_FUNC(llround);
376  DUNE_UNARY_FUNC(log);
377  DUNE_UNARY_FUNC(log10);
378  DUNE_UNARY_FUNC(log1p);
379  DUNE_UNARY_FUNC(log2);
380  DUNE_UNARY_FUNC(logb);
381  DUNE_UNARY_FUNC(lrint);
382  DUNE_UNARY_FUNC(lround);
383  // modf
384  DUNE_UNARY_FUNC(nearbyint);
385  // nextafter
386  // nexttoward
387  // pow
388  // remainder
389  // remquo
390  DUNE_UNARY_FUNC(rint);
392  // scalbln
393  // scalbn
394  DUNE_UNARY_FUNC(sin);
395  DUNE_UNARY_FUNC(sinh);
397  DUNE_UNARY_FUNC(tan);
398  DUNE_UNARY_FUNC(tanh);
399  DUNE_UNARY_FUNC(tgamma);
401 
402  DUNE_UNARY_FUNC(isfinite);
403  DUNE_UNARY_FUNC(isinf);
404  DUNE_UNARY_FUNC(isnan);
405  DUNE_UNARY_FUNC(isnormal);
406  DUNE_UNARY_FUNC(signbit);
407 
408  // isgreater
409  // isgreaterequal
410  // isless
411  // islessequal
412  // islessgreater
413  // isunordered
414 
415  //
416  // <complex> functions
417  //
418 
419  // not all functions are implemented, and unlike for <cmath>, no
420  // comprehensive list is provided
421  DUNE_UNARY_FUNC(real);
422 
423 #undef DUNE_UNARY_FUNC
424 
425  // We need to overload min() and max() since they require types to be
426  // LessThanComparable, which requires `a<b` to be "convertible to bool".
427  // That wording seems to be a leftover from C++03, and today is probably
428  // equivalent to "implicitly convertible". There is also issue 2114
429  // <https://cplusplus.github.io/LWG/issue2114> in the standard (still open
430  // as of 2018-07-06), which strives to require both "implicitly" and
431  // "contextually" convertible -- plus a few other things.
432  //
433  // We do not want our debug type to automatically decay to the underlying
434  // type, so we do not want to make the conversion non-explicit. So the
435  // only option left is to overload min() and max().
436 
437  template<class T, std::size_t align>
438  auto max(const AlignedNumber<T, align> &a,
439  const AlignedNumber<T, align> &b)
440  {
441  using std::max;
442  return aligned<align>(max(T(a), T(b)));
443  }
444 
445  template<class T, std::size_t align>
446  auto max(const T &a, const AlignedNumber<T, align> &b)
447  {
448  using std::max;
449  return aligned<align>(max(a, T(b)));
450  }
451 
452  template<class T, std::size_t align>
453  auto max(const AlignedNumber<T, align> &a, const T &b)
454  {
455  using std::max;
456  return aligned<align>(max(T(a), b));
457  }
458 
459  template<class T, std::size_t align>
460  auto min(const AlignedNumber<T, align> &a,
461  const AlignedNumber<T, align> &b)
462  {
463  using std::min;
464  return aligned<align>(min(T(a), T(b)));
465  }
466 
467  template<class T, std::size_t align>
468  auto min(const T &a, const AlignedNumber<T, align> &b)
469  {
470  using std::min;
471  return aligned<align>(min(a, T(b)));
472  }
473 
474  template<class T, std::size_t align>
475  auto min(const AlignedNumber<T, align> &a, const T &b)
476  {
477  using std::min;
478  return aligned<align>(min(T(a), b));
479  }
480 
481  } // namespace AlignedNumberImpl
482 
483  // SIMD-like functions from "conditional.hh"
484  template<class T, std::size_t align>
485  AlignedNumber<T, align>
486  cond(const AlignedNumber<bool, align> &b,
487  const AlignedNumber<T, align> &v1, const AlignedNumber<T, align> &v2)
488  {
489  return b ? v1 : v2;
490  }
491 
492  // SIMD-like functions from "rangeutilities.hh"
493  template<class T, std::size_t align>
494  T max_value(const AlignedNumber<T, align>& val)
495  {
496  return T(val);
497  }
498 
499  template<class T, std::size_t align>
500  T min_value(const AlignedNumber<T, align>& val)
501  {
502  return T(val);
503  }
504 
505  template<std::size_t align>
506  bool any_true(const AlignedNumber<bool, align>& val)
507  {
508  return bool(val);
509  }
510 
511  template<std::size_t align>
512  bool all_true(const AlignedNumber<bool, align>& val)
513  {
514  return bool(val);
515  }
516 
517  // SIMD-like functionality from "simd/interface.hh"
518  namespace Simd {
519  namespace Overloads {
520 
521  template<class T, std::size_t align>
522  struct ScalarType<AlignedNumber<T, align> > { using type = T; };
523 
524  template<class U, class T, std::size_t align>
525  struct RebindType<U, AlignedNumber<T, align> > {
526  using type = AlignedNumber<U, align>;
527  };
528 
529  template<class T, std::size_t align>
530  struct LaneCount<AlignedNumber<T, align> > : index_constant<1> {};
531 
532  template<class T, std::size_t align>
533  T& lane(ADLTag<5>, std::size_t l, AlignedNumber<T, align> &v)
534  {
535  assert(l == 0);
536  return v.value();
537  }
538 
539  template<class T, std::size_t align>
540  T lane(ADLTag<5>, std::size_t l, const AlignedNumber<T, align> &v)
541  {
542  assert(l == 0);
543  return v.value();
544  }
545 
546  template<class T, std::size_t align>
547  const AlignedNumber<T, align> &
548  cond(ADLTag<5>, AlignedNumber<bool, align> mask,
549  const AlignedNumber<T, align> &ifTrue,
550  const AlignedNumber<T, align> &ifFalse)
551  {
552  return mask ? ifTrue : ifFalse;
553  }
554 
555  template<std::size_t align>
556  bool anyTrue(ADLTag<5>, const AlignedNumber<bool, align> &mask)
557  {
558  return bool(mask);
559  }
560 
561  } // namespace Overloads
562 
563  } // namespace Simd
564 
565 } // namespace Dune
566 
567 #endif // DUNE_DEBUGALIGN_HH
AlignedNumber< U, align > type
Definition: debugalign.hh:526
T max_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:494
void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address)
called when an alignment violation is detected
Definition: debugalign.cc:36
ViolatedAlignmentHandler & violatedAlignmentHandler()
access the handler called by violatedAlignment()
Definition: debugalign.cc:30
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition: conditional.hh:28
std::istream & operator>>(std::istream &stream, std::tuple< Ts... > &t)
Read a std::tuple.
Definition: streamoperators.hh:43
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:407
bool all_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:512
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
bool isAligned(const void *p, std::size_t align)
check whether an address conforms to the given alignment
Definition: debugalign.hh:56
bool any_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:506
should have a member type type
Definition: base.hh:196
Dune namespace
Definition: alignedallocator.hh:12
A free function to provide the demangled class name of a given object or type as a string...
static constexpr auto debugAlignment
an alignment large enough to trigger alignment errors
Definition: debugalign.hh:97
#define DUNE_UNARY_FUNC(name)
#define DUNE_ASSIGN_OP(OP)
Definition: debugalign.hh:220
T min_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:500
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:511
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition: base.hh:182
T lane(std::size_t l, const T &v)
access a lane of a simd vector (scalar version)
Definition: simd.hh:366
Default implementations for SIMD ImplementationsThis file provides default overloads for SIMD impleme...
constexpr auto sqrt(T t) requires(std
Definition: cmath.hh:39
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:311
CRTP base mixin class to check alignment.
Definition: debugalign.hh:65
should be derived from a Dune::index_constant
Definition: base.hh:212
Basic definitions for SIMD ImplementationsThis file provides basic definitions and template declarati...
bool anyTrue(ADLTag< 5 >, const AlignedNumber< bool, align > &mask)
Definition: debugalign.hh:556
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:31
STL namespace.
Mask< V > mask(ADLTag< 0, std::is_same< V, Mask< V > >::value >, const V &v)
implements Simd::mask()
Definition: defaults.hh:153
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:114
Traits for type conversions and type information.
constexpr T abs(T t)
Definition: cmath.hh:27
should have a member type type
Definition: base.hh:204
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:47
#define DUNE_BINARY_OP(OP)
Definition: debugalign.hh:261