File: types.h

package info (click to toggle)
mrtrix3 3.0~rc3%2Bgit135-g2b8e7d0c2-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 34,248 kB
  • sloc: cpp: 117,101; python: 6,472; sh: 638; makefile: 226; xml: 39; ansic: 20
file content (328 lines) | stat: -rw-r--r-- 10,881 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*
 * Copyright (c) 2008-2018 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix3 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see http://www.mrtrix.org/
 */


#ifndef __mrtrix_types_h__
#define __mrtrix_types_h__

#include <cinttypes>
#include <complex>
#include <iostream>
#include <vector>
#include <deque>
#include <cstddef>
#include <memory>

#define NOMEMALIGN

#ifdef _WIN32
#  ifdef _WIN64
#    define PRI_SIZET PRIu64
#  else
#    define PRI_SIZET PRIu32
#  endif
#else
#  define PRI_SIZET "zu"
#endif


namespace MR {

#ifdef MRTRIX_MAX_ALIGN_T_NOT_DEFINED
# ifdef MRTRIX_STD_MAX_ALIGN_T_NOT_DEFINED
  // needed for clang 3.4:
  using __max_align_t = struct { NOMEMALIGN
    long long __clang_max_align_nonce1
        __attribute__((__aligned__(__alignof__(long long))));
    long double __clang_max_align_nonce2
        __attribute__((__aligned__(__alignof__(long double))));
  };
  constexpr size_t malloc_align = alignof (__max_align_t);
# else
  constexpr size_t malloc_align = alignof (std::max_align_t);
# endif
#else
  constexpr size_t malloc_align = alignof (::max_align_t);
#endif

  namespace Helper {
    template <class ImageType> class ConstRow;
    template <class ImageType> class Row;
  }
}

#ifdef EIGEN_HAS_OPENMP
# undef EIGEN_HAS_OPENMP
#endif

#define EIGEN_DENSEBASE_PLUGIN "eigen_plugins/dense_base.h"
#define EIGEN_MATRIXBASE_PLUGIN "eigen_plugins/dense_base.h"
#define EIGEN_ARRAYBASE_PLUGIN "eigen_plugins/dense_base.h"
#define EIGEN_MATRIX_PLUGIN "eigen_plugins/matrix.h"
#define EIGEN_ARRAY_PLUGIN "eigen_plugins/array.h"

#include <Eigen/Geometry>

/*! \defgroup VLA Variable-length array macros
 *
 * The reason for defining these macros at all is that VLAs are not part of the
 * C++ standard, and not available on all compilers. Regardless of the
 * availability of VLAs, they should be avoided if possible since they run the
 * risk of overrunning the stack if the length of the array is large, or if the
 * function is called recursively. They can be used safely in cases where the
 * size of the array is expected to be small, and the function will not be
 * called recursively, and in these cases may avoid the overhead of allocation
 * that might be incurred by the use of e.g. a vector.
 */

//! \{

/*! \def VLA
 * define a variable-length array (VLA) if supported by the compiler, or a
 * vector otherwise. This may have performance implications in the latter
 * case if this forms part of a tight loop.
 * \sa VLA_MAX
 */

/*! \def VLA_MAX
 * define a variable-length array if supported by the compiler, or a
 * fixed-length array of size \a max  otherwise. This may have performance
 * implications in the latter case if this forms part of a tight loop.
 * \note this should not be used in recursive functions, unless the maximum
 * number of calls is known to be small. Large amounts of recursion will run
 * the risk of overrunning the stack.
 * \sa VLA
 */


#ifdef MRTRIX_NO_VLA
# define VLA(name, type, num) \
  vector<type> __vla__ ## name(num); \
  type* name = &__vla__ ## name[0]
# define VLA_MAX(name, type, num, max) type name[max]
#else
# define VLA(name, type, num) type name[num]
# define VLA_MAX(name, type, num, max) type name[num]
#endif


/*! \def NON_POD_VLA
 * define a variable-length array of non-POD data if supported by the compiler,
 * or a vector otherwise. This may have performance implications in the
 * latter case if this forms part of a tight loop.
 * \sa VLA_MAX
 */

/*! \def NON_POD_VLA_MAX
 * define a variable-length array of non-POD data if supported by the compiler,
 * or a fixed-length array of size \a max  otherwise. This may have performance
 * implications in the latter case if this forms part of a tight loop.
 * \note this should not be used in recursive functions, unless the maximum
 * number of calls is known to be small. Large amounts of recursion will run
 * the risk of overrunning the stack.
 * \sa VLA
 */


#ifdef MRTRIX_NO_NON_POD_VLA
# define NON_POD_VLA(name, type, num) \
  vector<type> __vla__ ## name(num); \
  type* name = &__vla__ ## name[0]
# define NON_POD_VLA_MAX(name, type, num, max) type name[max]
#else
# define NON_POD_VLA(name, type, num) type name[num]
# define NON_POD_VLA_MAX(name, type, num, max) type name[num]
#endif

//! \}

#ifdef NDEBUG
# define FORCE_INLINE inline __attribute__((always_inline))
#else // don't force inlining in debug mode, so we can get more informative backtraces
# define FORCE_INLINE inline
#endif


#ifndef EIGEN_DEFAULT_ALIGN_BYTES
// Assume 16 byte alignment as hard-coded in Eigen 3.2:
# define EIGEN_DEFAULT_ALIGN_BYTES 16
#endif


template <class T> class __has_custom_new_operator { NOMEMALIGN
    template <typename C> static inline char test (decltype(C::operator new (sizeof(C)))) ;
    template <typename C> static inline long test (...);
  public:
    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) };
};


inline void* __aligned_malloc (std::size_t size) {
  auto* original = std::malloc (size + EIGEN_DEFAULT_ALIGN_BYTES);
  if (!original) throw std::bad_alloc();
  void *aligned = reinterpret_cast<void*>((reinterpret_cast<std::size_t>(original) & ~(std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1))) + EIGEN_DEFAULT_ALIGN_BYTES);
  *(reinterpret_cast<void**>(aligned) - 1) = original;
  return aligned;
}

inline void __aligned_free (void* ptr) { if (ptr) std::free (*(reinterpret_cast<void**>(ptr) - 1)); }


#define MEMALIGN(...) public: \
  FORCE_INLINE void* operator new (std::size_t size) { return (alignof(__VA_ARGS__)>::MR::malloc_align) ? __aligned_malloc (size) : ::operator new (size); } \
  FORCE_INLINE void* operator new[] (std::size_t size) { return (alignof(__VA_ARGS__)>::MR::malloc_align) ? __aligned_malloc (size) : ::operator new[] (size); } \
  FORCE_INLINE void operator delete (void* ptr) { if (alignof(__VA_ARGS__)>::MR::malloc_align) __aligned_free (ptr); else ::operator delete (ptr); } \
  FORCE_INLINE void operator delete[] (void* ptr) { if (alignof(__VA_ARGS__)>::MR::malloc_align) __aligned_free (ptr); else ::operator delete[] (ptr); }


/*! \def CHECK_MEM_ALIGN
 * used to verify that the class is set up approriately for memory alignment
 * when dynamically allocated. This checks whether the class's alignment
 * requirements exceed that of the default allocator, and if so whether it has
 * custom operator new methods defined to deal with this. Conversely, it also
 * checks whether a custom allocator has been defined needlessly, which is to
 * be avoided for performance reasons.
 *
 * The compiler will check whether this is indeed needed, and fail with an
 * appropriate warning if this is not true. In this case, you need to replace
 * MEMALIGN with NOMEMALIGN.
 * \sa NOMEMALIGN
 * \sa MEMALIGN
 */
#define CHECK_MEM_ALIGN(...) \
    static_assert ( (alignof(__VA_ARGS__) <= ::MR::malloc_align) || __has_custom_new_operator<__VA_ARGS__>::value, \
        "class requires over-alignment, but no operator new defined! Please insert MEMALIGN() into class definition.")



namespace MR
{

  using float32 = float;
  using float64 = double;
  using cdouble = std::complex<double>;
  using cfloat  = std::complex<float>;

  template <typename T>
    struct container_cast : public T { MEMALIGN(container_cast<T>)
      template <typename U>
        container_cast (const U& x) :
        T (x.begin(), x.end()) { }
    };

  //! the default type used throughout MRtrix
  using default_type = double;

  constexpr default_type NaN = std::numeric_limits<default_type>::quiet_NaN();
  constexpr default_type Inf = std::numeric_limits<default_type>::infinity();

  //! the type for the affine transform of an image:
  using transform_type = Eigen::Transform<default_type, 3, Eigen::AffineCompact>;


  //! check whether type is complex:
  template <class ValueType> struct is_complex : std::false_type { NOMEMALIGN };
  template <class ValueType> struct is_complex<std::complex<ValueType>> : std::true_type { NOMEMALIGN };


  //! check whether type is compatible with MRtrix3's file IO backend:
  template <class ValueType>
    struct is_data_type :
      std::integral_constant<bool, std::is_arithmetic<ValueType>::value || is_complex<ValueType>::value> { NOMEMALIGN };


  template <typename X, int N=(alignof(X)>::MR::malloc_align)>
    class vector : public ::std::vector<X, Eigen::aligned_allocator<X>> { NOMEMALIGN
      public:
        using ::std::vector<X,Eigen::aligned_allocator<X>>::vector;
        vector() { }
    };

  template <typename X>
    class vector<X,0> : public ::std::vector<X> { NOMEMALIGN
      public:
        using ::std::vector<X>::vector;
        vector() { }
    };


  template <typename X, int N=(alignof(X)>::MR::malloc_align)>
    class deque : public ::std::deque<X, Eigen::aligned_allocator<X>> { NOMEMALIGN
      public:
        using ::std::deque<X,Eigen::aligned_allocator<X>>::deque;
        deque() { }
    };

  template <typename X>
    class deque<X,0> : public ::std::deque<X> { NOMEMALIGN
      public:
        using ::std::deque<X>::deque;
        deque() { }
    };


  template <typename X, typename... Args>
    inline std::shared_ptr<X> make_shared (Args&&... args) {
      return std::shared_ptr<X> (new X (std::forward<Args> (args)...));
    }

  template <typename X, typename... Args>
    inline std::unique_ptr<X> make_unique (Args&&... args) {
      return std::unique_ptr<X> (new X (std::forward<Args> (args)...));
    }


  // required to allow use of abs() call on unsigned integers in template
  // functions, etc, since the standard labels such calls ill-formed:
  // http://en.cppreference.com/w/cpp/numeric/math/abs
  template <typename X>
    inline constexpr typename std::enable_if<std::is_arithmetic<X>::value && std::is_unsigned<X>::value,X>::type abs (X x) { return x; }
  template <typename X>
    inline constexpr typename std::enable_if<std::is_arithmetic<X>::value && !std::is_unsigned<X>::value,X>::type abs (X x) { return std::abs(x); }
}

namespace std
{

  template <class T> inline ostream& operator<< (ostream& stream, const vector<T>& V)
  {
    stream << "[ ";
    for (size_t n = 0; n < V.size(); n++)
      stream << V[n] << " ";
    stream << "]";
    return stream;
  }

  template <class T, std::size_t N> inline ostream& operator<< (ostream& stream, const array<T,N>& V)
  {
    stream << "[ ";
    for (size_t n = 0; n < N; n++)
      stream << V[n] << " ";
    stream << "]";
    return stream;
  }

}

namespace Eigen {
  using Vector3 = Matrix<MR::default_type, 3, 1>;
  using Vector4 = Matrix<MR::default_type, 4, 1>;
}

#endif