Dune Core Modules (2.6.0)

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 <cmath>
7 #include <complex>
8 #include <cstddef>
9 #include <cstdint>
10 #include <cstdlib> // abs
11 #include <functional>
12 #include <istream>
13 #include <ostream>
14 #include <type_traits>
15 #include <utility>
16 
17 #include <dune/common/classname.hh>
19 #include <dune/common/simd.hh>
20 
21 namespace Dune {
22 
25  std::function<void(const char*, std::size_t, const void*)>;
26 
28 
35 
37 
46  void violatedAlignment(const char *className, std::size_t expectedAlignment,
47  const void *address);
48 
50  inline bool isAligned(const void *p, std::size_t align)
51  {
52  // a more portable way to do this would be to abuse std::align(), but that
53  // isn't supported by g++-4.9 yet
54  return std::uintptr_t(p) % align == 0;
55  }
56 
58  template<std::size_t align, class Impl>
59  class alignas(align) AlignedBase
60  {
61  void checkAlignment() const
62  {
63  auto pimpl = static_cast<const Impl*>(this);
64  if(!isAligned(pimpl, align))
65  violatedAlignment(className<Impl>().c_str(), align, pimpl);
66  }
67  public:
68  AlignedBase() { checkAlignment(); }
69  AlignedBase(const AlignedBase &) { checkAlignment(); }
70  AlignedBase(AlignedBase &&) { checkAlignment(); }
71  ~AlignedBase() { checkAlignment(); }
72 
73  AlignedBase& operator=(const AlignedBase &) = default;
74  AlignedBase& operator=(AlignedBase &&) = default;
75  };
76 
78  static constexpr auto debugAlignment = 2*alignof(std::max_align_t);
79 
80  namespace AlignedNumberImpl {
81 
82  template<class T, std::size_t align = debugAlignment>
83  class AlignedNumber;
84 
85  } // namespace AlignedNumberImpl
86 
87  using AlignedNumberImpl::AlignedNumber;
88 
90  template<std::size_t align = debugAlignment, class T>
91  AlignedNumber<T, align> aligned(T value) { return { std::move(value) }; }
92 
93  // The purpose of this namespace is to move the `<cmath>` function overloads
94  // out of namespace `Dune`. This avoids problems where people called
95  // e.g. `sqrt(1.0)` inside the `Dune` namespace, without first doing `using
96  // std::sqrt;`. Without any `Dune::sqrt()`, such a use will find
97  // `::sqrt()`, but with `Dune::sqrt()` it will find only `Dune::sqrt()`,
98  // which does not have an overload for `double`.
99  namespace AlignedNumberImpl {
100 
102  template<class T, std::size_t align>
104  : public AlignedBase<align, AlignedNumber<T, align> >
105  {
106  T value_;
107 
108  public:
109  AlignedNumber() = default;
110  AlignedNumber(T value) : value_(std::move(value)) {}
111  template<class U, std::size_t uAlign,
112  class = std::enable_if_t<(align >= uAlign) &&
113  std::is_convertible<U, T>::value> >
114  AlignedNumber(const AlignedNumber<U, uAlign> &o) : value_(U(o)) {}
115 
116  template<class U,
117  class = std::enable_if_t<std::is_convertible<T, U>::value> >
118  explicit operator U() const { return value_; }
119 
120  // I/O
121  template<class charT, class Traits>
122  friend std::basic_istream<charT, Traits>&
123  operator>>(std::basic_istream<charT, Traits>& str, AlignedNumber &u)
124  {
125  return str >> u.value_;
126  }
127 
128  template<class charT, class Traits>
129  friend std::basic_ostream<charT, Traits>&
130  operator<<(std::basic_ostream<charT, Traits>& str,
131  const AlignedNumber &u)
132  {
133  return str << u.value_;
134  }
135 
136  // The trick with `template<class U = T, class = void_t<expr(U)> >` is
137  // needed because at least g++-4.9 seems to evaluates a default argument
138  // in `template<class = void_t<expr(T))> >` as soon as possible and will
139  // error out if `expr(T)` is invalid. E.g. for `expr(T)` =
140  // `decltype(--std::declval<T&>())`, instantiating `AlignedNumber<bool>`
141  // will result in an unrecoverable error (`--` cannot be applied to a
142  // `bool`).
143 
144  // Increment, decrement
145  template<class U = T, class = void_t<decltype(++std::declval<U&>())> >
146  AlignedNumber &operator++() { ++value_; return *this; }
147 
148  template<class U = T, class = void_t<decltype(--std::declval<U&>())> >
149  AlignedNumber &operator--() { --value_; return *this; }
150 
151  template<class U = T, class = void_t<decltype(std::declval<U&>()++)> >
152  decltype(auto) operator++(int) { return aligned<align>(value_++); }
153 
154  template<class U = T, class = void_t<decltype(std::declval<U&>()--)> >
155  decltype(auto) operator--(int) { return aligned<align>(value_--); }
156 
157  // unary operators
158  template<class U = T,
160  decltype(auto) operator+() const { return aligned<align>(+value_); }
161 
162  template<class U = T,
163  class = void_t<decltype(-std::declval<const U&>())> >
164  decltype(auto) operator-() const { return aligned<align>(-value_); }
165 
166  template<class U = T,
168  decltype(auto) operator~() const { return aligned<align>(~value_); }
169 
170  template<class U = T,
172  decltype(auto) operator!() const { return aligned<align>(!value_); }
173 
174  // assignment operators
175 #define DUNE_ASSIGN_OP(OP) \
176  template<class U, std::size_t uAlign, \
177  class = std::enable_if_t< \
178  ( uAlign <= align && \
179  sizeof(std::declval<T&>() OP std::declval<U>()) ) \
180  > > \
181  AlignedNumber &operator OP(const AlignedNumber<U, uAlign> &u) \
182  { \
183  value_ OP U(u); \
184  return *this; \
185  } \
186  \
187  template<class U, \
188  class = void_t<decltype(std::declval<T&>() OP \
189  std::declval<U>())> > \
190  AlignedNumber &operator OP(const U &u) \
191  { \
192  value_ OP u; \
193  return *this; \
194  } \
195  \
196  static_assert(true, "Require semicolon to unconfuse editors")
197 
198  DUNE_ASSIGN_OP(+=);
199  DUNE_ASSIGN_OP(-=);
200 
201  DUNE_ASSIGN_OP(*=);
202  DUNE_ASSIGN_OP(/=);
203  DUNE_ASSIGN_OP(%=);
204 
205  DUNE_ASSIGN_OP(^=);
206  DUNE_ASSIGN_OP(&=);
207  DUNE_ASSIGN_OP(|=);
208 
209  DUNE_ASSIGN_OP(<<=);
210  DUNE_ASSIGN_OP(>>=);
211 
212 #undef DUNE_ASSIGN_OP
213  };
214 
215  // binary operators
216 #define DUNE_BINARY_OP(OP) \
217  template<class T, std::size_t tAlign, class U, std::size_t uAlign, \
218  class = void_t<decltype(std::declval<T>() \
219  OP std::declval<U>())> > \
220  decltype(auto) \
221  operator OP(const AlignedNumber<T, tAlign> &t, \
222  const AlignedNumber<U, uAlign> &u) \
223  { \
224  /* can't use std::max(); not constexpr */ \
225  return aligned<(tAlign > uAlign ? tAlign : uAlign)>(T(t) OP U(u)); \
226  } \
227  \
228  template<class T, class U, std::size_t uAlign, \
229  class = void_t<decltype(std::declval<T>() \
230  OP std::declval<U>())> > \
231  decltype(auto) \
232  operator OP(const T &t, const AlignedNumber<U, uAlign> &u) \
233  { \
234  return aligned<uAlign>(t OP U(u)); \
235  } \
236  \
237  template<class T, std::size_t tAlign, class U, \
238  class = void_t<decltype(std::declval<T>() \
239  OP std::declval<U>())> > \
240  decltype(auto) \
241  operator OP(const AlignedNumber<T, tAlign> &t, const U &u) \
242  { \
243  return aligned<tAlign>(T(t) OP u); \
244  } \
245  \
246  static_assert(true, "Require semicolon to unconfuse editors")
247 
248  DUNE_BINARY_OP(+);
249  DUNE_BINARY_OP(-);
250 
251  DUNE_BINARY_OP(*);
252  DUNE_BINARY_OP(/);
253  DUNE_BINARY_OP(%);
254 
255  DUNE_BINARY_OP(^);
256  DUNE_BINARY_OP(&);
257  DUNE_BINARY_OP(|);
258 
259  DUNE_BINARY_OP(<<);
260  DUNE_BINARY_OP(>>);
261 
262  DUNE_BINARY_OP(==);
263  DUNE_BINARY_OP(!=);
264  DUNE_BINARY_OP(<);
265  DUNE_BINARY_OP(>);
266  DUNE_BINARY_OP(<=);
267  DUNE_BINARY_OP(>=);
268 
269  DUNE_BINARY_OP(&&);
270  DUNE_BINARY_OP(||);
271 
272 #undef DUNE_BINARY_OP
273 
275  //
276  // Overloads for the functions provided by the standard library
277  //
278 #define DUNE_UNARY_FUNC(name) \
279  template<class T, std::size_t align> \
280  decltype(auto) name(const AlignedNumber<T, align> &u) \
281  { \
282  using std::name; \
283  return aligned<align>(name(T(u))); \
284  }
285 
286  //
287  // <cmath> functions
288  //
289 
290  // note: only unary functions are provided at the moment. Getting all the
291  // overloads right for functions with more than one aregument is tricky.
292  // All <cmath> functions appear in the list below in the order they are
293  // listet in in the standard, but the unimplemented ones are commented
294  // out.
295 
296  // note: abs is provided by both <cstdlib> (for integer) and <cmath> (for
297  // floating point). This overload works for both.
298  DUNE_UNARY_FUNC(abs);
299  DUNE_UNARY_FUNC(acos);
300  DUNE_UNARY_FUNC(acosh);
301  DUNE_UNARY_FUNC(asin);
302  DUNE_UNARY_FUNC(asinh);
303  DUNE_UNARY_FUNC(atan);
304  // atan2
305  DUNE_UNARY_FUNC(atanh);
306  DUNE_UNARY_FUNC(cbrt);
307  DUNE_UNARY_FUNC(ceil);
308  // copysign
309  DUNE_UNARY_FUNC(cos);
310  DUNE_UNARY_FUNC(cosh);
311  DUNE_UNARY_FUNC(erf);
312  DUNE_UNARY_FUNC(erfc);
313  DUNE_UNARY_FUNC(exp);
314  DUNE_UNARY_FUNC(exp2);
315  DUNE_UNARY_FUNC(expm1);
316  DUNE_UNARY_FUNC(fabs);
317  // fdim
318  DUNE_UNARY_FUNC(floor);
319  // fma
320  // fmax
321  // fmin
322  // fmod
323  // frexp
324  // hypos
325  DUNE_UNARY_FUNC(ilogb);
326  // ldexp
327  DUNE_UNARY_FUNC(lgamma);
328  DUNE_UNARY_FUNC(llrint);
329  DUNE_UNARY_FUNC(llround);
330  DUNE_UNARY_FUNC(log);
331  DUNE_UNARY_FUNC(log10);
332  DUNE_UNARY_FUNC(log1p);
333  DUNE_UNARY_FUNC(log2);
334  DUNE_UNARY_FUNC(logb);
335  DUNE_UNARY_FUNC(lrint);
336  DUNE_UNARY_FUNC(lround);
337  // modf
338  DUNE_UNARY_FUNC(nearbyint);
339  // nextafter
340  // nexttoward
341  // pow
342  // remainder
343  // remquo
344  DUNE_UNARY_FUNC(rint);
345  DUNE_UNARY_FUNC(round);
346  // scalbln
347  // scalbn
348  DUNE_UNARY_FUNC(sin);
349  DUNE_UNARY_FUNC(sinh);
350  DUNE_UNARY_FUNC(sqrt);
351  DUNE_UNARY_FUNC(tan);
352  DUNE_UNARY_FUNC(tanh);
353  DUNE_UNARY_FUNC(tgamma);
354  DUNE_UNARY_FUNC(trunc);
355 
356  DUNE_UNARY_FUNC(isfinite);
357  DUNE_UNARY_FUNC(isinf);
358  DUNE_UNARY_FUNC(isnan);
359  DUNE_UNARY_FUNC(isnormal);
360  DUNE_UNARY_FUNC(signbit);
361 
362  // isgreater
363  // isgreaterequal
364  // isless
365  // islessequal
366  // islessgreater
367  // isunordered
368 
369  //
370  // <complex> functions
371  //
372 
373  // not all functions are implemented, und unlike for <cmath>, no
374  // comprehensive list is provided
375  DUNE_UNARY_FUNC(real);
376 
377 #undef DUNE_UNARY_FUNC
378 
379  } // namespace AlignedNumberImpl
380 
381  // SIMD-like functions
382  template<class T, std::size_t align>
386  {
387  return b ? v1 : v2;
388  }
389 
390  template<class T, std::size_t align>
391  T max_value(const AlignedNumber<T, align>& val)
392  {
393  return T(val);
394  }
395 
396  template<class T, std::size_t align>
397  T min_value(const AlignedNumber<T, align>& val)
398  {
399  return T(val);
400  }
401 
402  template<std::size_t align>
403  bool any_true(const AlignedNumber<bool, align>& val)
404  {
405  return bool(val);
406  }
407 
408  template<std::size_t align>
409  bool all_true(const AlignedNumber<bool, align>& val)
410  {
411  return bool(val);
412  }
413 
415  template<typename T, std::size_t align>
416  struct SimdScalarTypeTraits< AlignedNumber<T,align> >
417  {
418  using type = T;
419  };
420 
421 } // namespace Dune
422 
423 #endif // DUNE_DEBUGALIGN_HH
CRTP base mixin class to check alignment.
Definition: debugalign.hh:60
aligned wrappers for arithmetic types
Definition: debugalign.hh:105
A free function to provide the demangled class name of a given object or type as a string.
Stream & operator>>(Stream &stream, std::tuple< Ts... > &t)
Read a std::tuple.
Definition: streamoperators.hh:41
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:39
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:300
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:396
Dune namespace.
Definition: alignedallocator.hh:10
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:91
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:26
static constexpr auto debugAlignment
an alignment large enough to trigger alignment errors
Definition: debugalign.hh:78
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:50
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:25
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (Apr 27, 22:29, 2024)