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
19#include <dune/common/simd.hh>
20
21namespace 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
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
AlignedNumber< T, align > aligned(T value)
align a value to a certain alignment
Definition: debugalign.hh:91
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.111.3 (Dec 26, 23:30, 2024)