Dune Core Modules (2.7.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 #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;
78  AlignedBase& operator=(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 
91  using AlignedNumberImpl::AlignedNumber;
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 = void_t<expr(U)> >` is
145  // needed because at least g++-4.9 seems to evaluates a default argument
146  // in `template<class = 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 = void_t<decltype(++std::declval<U&>())> >
154  AlignedNumber &operator++() { ++value_; return *this; }
155 
156  template<class U = T, class = void_t<decltype(--std::declval<U&>())> >
157  AlignedNumber &operator--() { --value_; return *this; }
158 
159  template<class U = T, class = void_t<decltype(std::declval<U&>()++)> >
160  decltype(auto) operator++(int) { return aligned<align>(value_++); }
161 
162  template<class U = T, class = void_t<decltype(std::declval<U&>()--)> >
163  decltype(auto) operator--(int) { return aligned<align>(value_--); }
164 
165  // unary operators
166  template<class U = T,
168  decltype(auto) operator+() const { return aligned<align>(+value_); }
169 
170  template<class U = T,
171  class = 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,
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,
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 = 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 
217  DUNE_ASSIGN_OP(+=);
218  DUNE_ASSIGN_OP(-=);
219 
220  DUNE_ASSIGN_OP(*=);
221  DUNE_ASSIGN_OP(/=);
222  DUNE_ASSIGN_OP(%=);
223 
224  DUNE_ASSIGN_OP(^=);
225  DUNE_ASSIGN_OP(&=);
226  DUNE_ASSIGN_OP(|=);
227 
228  DUNE_ASSIGN_OP(<<=);
229  DUNE_ASSIGN_OP(>>=);
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 = 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 = 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 = 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 
267  DUNE_BINARY_OP(+);
268  DUNE_BINARY_OP(-);
269 
270  DUNE_BINARY_OP(*);
271  DUNE_BINARY_OP(/);
272  DUNE_BINARY_OP(%);
273 
274  DUNE_BINARY_OP(^);
275  DUNE_BINARY_OP(&);
276  DUNE_BINARY_OP(|);
277 
278  DUNE_BINARY_OP(<<);
279  DUNE_BINARY_OP(>>);
280 
281  DUNE_BINARY_OP(==);
282  DUNE_BINARY_OP(!=);
283  DUNE_BINARY_OP(<);
284  DUNE_BINARY_OP(>);
285  DUNE_BINARY_OP(<=);
286  DUNE_BINARY_OP(>=);
287 
288  DUNE_BINARY_OP(&&);
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);
319  DUNE_UNARY_FUNC(acos);
320  DUNE_UNARY_FUNC(acosh);
321  DUNE_UNARY_FUNC(asin);
322  DUNE_UNARY_FUNC(asinh);
323  DUNE_UNARY_FUNC(atan);
324  // atan2
325  DUNE_UNARY_FUNC(atanh);
326  DUNE_UNARY_FUNC(cbrt);
327  DUNE_UNARY_FUNC(ceil);
328  // copysign
329  DUNE_UNARY_FUNC(cos);
330  DUNE_UNARY_FUNC(cosh);
331  DUNE_UNARY_FUNC(erf);
332  DUNE_UNARY_FUNC(erfc);
333  DUNE_UNARY_FUNC(exp);
334  DUNE_UNARY_FUNC(exp2);
335  DUNE_UNARY_FUNC(expm1);
336  DUNE_UNARY_FUNC(fabs);
337  // fdim
338  DUNE_UNARY_FUNC(floor);
339  // fma
340  // fmax
341  // fmin
342  // fmod
343  // frexp
344  // hypos
345  DUNE_UNARY_FUNC(ilogb);
346  // ldexp
347  DUNE_UNARY_FUNC(lgamma);
348  DUNE_UNARY_FUNC(llrint);
349  DUNE_UNARY_FUNC(llround);
350  DUNE_UNARY_FUNC(log);
351  DUNE_UNARY_FUNC(log10);
352  DUNE_UNARY_FUNC(log1p);
353  DUNE_UNARY_FUNC(log2);
354  DUNE_UNARY_FUNC(logb);
355  DUNE_UNARY_FUNC(lrint);
356  DUNE_UNARY_FUNC(lround);
357  // modf
358  DUNE_UNARY_FUNC(nearbyint);
359  // nextafter
360  // nexttoward
361  // pow
362  // remainder
363  // remquo
364  DUNE_UNARY_FUNC(rint);
365  DUNE_UNARY_FUNC(round);
366  // scalbln
367  // scalbn
368  DUNE_UNARY_FUNC(sin);
369  DUNE_UNARY_FUNC(sinh);
370  DUNE_UNARY_FUNC(sqrt);
371  DUNE_UNARY_FUNC(tan);
372  DUNE_UNARY_FUNC(tanh);
373  DUNE_UNARY_FUNC(tgamma);
374  DUNE_UNARY_FUNC(trunc);
375 
376  DUNE_UNARY_FUNC(isfinite);
377  DUNE_UNARY_FUNC(isinf);
378  DUNE_UNARY_FUNC(isnan);
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
395  DUNE_UNARY_FUNC(real);
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>
412  auto max(const AlignedNumber<T, align> &a,
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>
434  auto min(const AlignedNumber<T, align> &a,
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>
460  cond(const AlignedNumber<bool, align> &b,
461  const AlignedNumber<T, align> &v1, const AlignedNumber<T, align> &v2)
462  {
463  return b ? v1 : v2;
464  }
465 
466  // SIMD-like functions from "rangeutilities.hh"
467  template<class T, std::size_t align>
468  T max_value(const AlignedNumber<T, align>& val)
469  {
470  return T(val);
471  }
472 
473  template<class T, std::size_t align>
474  T min_value(const AlignedNumber<T, align>& val)
475  {
476  return T(val);
477  }
478 
479  template<std::size_t align>
480  bool any_true(const AlignedNumber<bool, align>& val)
481  {
482  return bool(val);
483  }
484 
485  template<std::size_t align>
486  bool all_true(const AlignedNumber<bool, align>& val)
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> > {
500  using type = AlignedNumber<U, 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
Basic definitions for SIMD Implementations.
CRTP base mixin class to check alignment.
Definition: debugalign.hh:64
aligned wrappers for arithmetic types
Definition: debugalign.hh:109
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:41
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 (see N3911). 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: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
auto min(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::min()
Definition: defaults.hh:87
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:79
Dune namespace.
Definition: alignedallocator.hh:14
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
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:44
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
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:29
Tag used to force late-binding lookup in Dune::Simd::Overloads.
Definition: base.hh:180
should be derived from a Dune::index_constant
Definition: standard.hh:72
should have a member type type
Definition: standard.hh:65
should have a member type type
Definition: standard.hh:58
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)