dune-common  2.6-git
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 <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>
84 
85  } // namespace AlignedNumberImpl
86 
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>
103  class AlignedNumber
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);
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);
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>
383  AlignedNumber<T, align>
386  {
387  return b ? v1 : v2;
388  }
389 
390  template<class T, std::size_t align>
392  {
393  return T(val);
394  }
395 
396  template<class T, std::size_t align>
398  {
399  return T(val);
400  }
401 
402  template<std::size_t align>
404  {
405  return bool(val);
406  }
407 
408  template<std::size_t align>
410  {
411  return bool(val);
412  }
413 
415  template<typename T, std::size_t align>
417  {
418  using type = T;
419  };
420 
421 } // namespace Dune
422 
423 #endif // DUNE_DEBUGALIGN_HH
Dune::SimdScalarTypeTraits
Definition: simd.hh:182
Dune::all_true
bool all_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:409
Dune::AlignedNumberImpl::AlignedNumber::operator--
AlignedNumber & operator--()
Definition: debugalign.hh:149
Dune::AlignedNumberImpl::AlignedNumber::AlignedNumber
AlignedNumber(const AlignedNumber< U, uAlign > &o)
Definition: debugalign.hh:114
Dune::ViolatedAlignmentHandler
std::function< void(const char *, std::size_t, const void *)> ViolatedAlignmentHandler
type of the handler called by violatedAlignment()
Definition: debugalign.hh:25
Dune::AlignedBase::AlignedBase
AlignedBase(const AlignedBase &)
Definition: debugalign.hh:69
Dune
Dune namespace.
Definition: alignedallocator.hh:9
Dune::FloatCmp::trunc
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition: float_cmp.cc:396
Dune::debugAlignment
static constexpr auto debugAlignment
an alignment large enough to trigger alignment errors
Definition: debugalign.hh:78
Dune::SimdScalarTypeTraits< AlignedNumber< T, align > >::type
T type
Definition: debugalign.hh:418
Dune::violatedAlignment
void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address)
called when an alignment violation is detected
Definition: debugalign.cc:37
Dune::aligned
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:91
classname.hh
A free function to provide the demangled class name of a given object or type as a string.
Dune::violatedAlignmentHandler
ViolatedAlignmentHandler & violatedAlignmentHandler()
access the handler called by violatedAlignment()
Definition: debugalign.cc:31
simd.hh
Dune::AlignedNumberImpl::AlignedNumber::operator~
decltype(auto) operator~() const
Definition: debugalign.hh:168
Dune::AlignedNumberImpl::AlignedNumber
aligned wrappers for arithmetic types
Definition: debugalign.hh:83
Dune::AlignedNumberImpl::AlignedNumber::AlignedNumber
AlignedNumber(T value)
Definition: debugalign.hh:110
Dune::className
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:26
DUNE_UNARY_FUNC
#define DUNE_UNARY_FUNC(name)
Dune::void_t
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
Dune::AlignedBase
CRTP base mixin class to check alignment.
Definition: debugalign.hh:59
Dune::AlignedNumberImpl::AlignedNumber::operator>>
friend std::basic_istream< charT, Traits > & operator>>(std::basic_istream< charT, Traits > &str, AlignedNumber &u)
Definition: debugalign.hh:123
Dune::AlignedNumberImpl::AlignedNumber::operator!
decltype(auto) operator!() const
Definition: debugalign.hh:172
Dune::AlignedBase::~AlignedBase
~AlignedBase()
Definition: debugalign.hh:71
Dune::cond
const T1 cond(bool b, const T1 &v1, const T2 &v2)
conditional evaluate
Definition: conditional.hh:26
Dune::AlignedNumberImpl::AlignedNumber::operator+
decltype(auto) operator+() const
Definition: debugalign.hh:160
Dune::any_true
bool any_true(const AlignedNumber< bool, align > &val)
Definition: debugalign.hh:403
Dune::operator<<
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:272
Dune::max_value
T max_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:391
Dune::AlignedBase::AlignedBase
AlignedBase(AlignedBase &&)
Definition: debugalign.hh:70
DUNE_BINARY_OP
#define DUNE_BINARY_OP(OP)
Definition: debugalign.hh:216
DUNE_ASSIGN_OP
#define DUNE_ASSIGN_OP(OP)
Definition: debugalign.hh:175
Dune::AlignedNumberImpl::AlignedNumber::operator--
decltype(auto) operator--(int)
Definition: debugalign.hh:155
Dune::AlignedBase::AlignedBase
AlignedBase()
Definition: debugalign.hh:68
Dune::AlignedNumberImpl::AlignedNumber::operator++
decltype(auto) operator++(int)
Definition: debugalign.hh:152
typetraits.hh
Traits for type conversions and type information.
Dune::FloatCmp::round
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition: float_cmp.cc:300
Dune::isAligned
bool isAligned(const void *p, std::size_t align)
check whether an address conforms to the given alignment
Definition: debugalign.hh:50
Dune::min_value
T min_value(const AlignedNumber< T, align > &val)
Definition: debugalign.hh:397