1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
12/**
13 * @file types.h
14 * @brief Typedefs for easier changing of types
15 * @author Richard Roberts
16 * @date Aug 21, 2010
17 * @ingroup base
18 */
19
20#pragma once
21
22#include <gtsam/config.h> // for GTSAM_USE_TBB
23#include <gtsam/dllexport.h>
24
25#include <cstddef>
26#include <cstdint>
27#include <exception>
28#include <string>
29
30#ifdef GTSAM_USE_TBB
31#include <tbb/scalable_allocator.h>
32#endif
33
34#if defined(__GNUC__) || defined(__clang__)
35#define GTSAM_DEPRECATED __attribute__((deprecated))
36#elif defined(_MSC_VER)
37#define GTSAM_DEPRECATED __declspec(deprecated)
38#else
39#define GTSAM_DEPRECATED
40#endif
41
42#ifdef GTSAM_USE_EIGEN_MKL_OPENMP
43#include <omp.h>
44#endif
45
46/* Define macros for ignoring compiler warnings.
47 * Usage Example:
48 * ```
49 * CLANG_DIAGNOSTIC_PUSH_IGNORE("-Wdeprecated-declarations")
50 * GCC_DIAGNOSTIC_PUSH_IGNORE("-Wdeprecated-declarations")
51 * MSVC_DIAGNOSTIC_PUSH_IGNORE(4996)
52 * // ... code you want to suppress deprecation warnings for ...
53 * DIAGNOSTIC_POP()
54 * ```
55 */
56#define DO_PRAGMA(x) _Pragma (#x)
57#ifdef __clang__
58# define CLANG_DIAGNOSTIC_PUSH_IGNORE(diag) \
59 _Pragma("clang diagnostic push") \
60 DO_PRAGMA(clang diagnostic ignored diag)
61#else
62# define CLANG_DIAGNOSTIC_PUSH_IGNORE(diag)
63#endif
64
65#ifdef __GNUC__
66# define GCC_DIAGNOSTIC_PUSH_IGNORE(diag) \
67 _Pragma("GCC diagnostic push") \
68 DO_PRAGMA(GCC diagnostic ignored diag)
69#else
70# define GCC_DIAGNOSTIC_PUSH_IGNORE(diag)
71#endif
72
73#ifdef _MSC_VER
74# define MSVC_DIAGNOSTIC_PUSH_IGNORE(code) \
75 _Pragma("warning ( push )") \
76 DO_PRAGMA(warning ( disable : code ))
77#else
78# define MSVC_DIAGNOSTIC_PUSH_IGNORE(code)
79#endif
80
81#if defined(__clang__)
82# define DIAGNOSTIC_POP() _Pragma("clang diagnostic pop")
83#elif defined(__GNUC__)
84# define DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop")
85#elif defined(_MSC_VER)
86# define DIAGNOSTIC_POP() _Pragma("warning ( pop )")
87#else
88# define DIAGNOSTIC_POP()
89#endif
90
91namespace gtsam {
92
93 /// Function to demangle type name of variable, e.g. demangle(typeid(x).name())
94 std::string GTSAM_EXPORT demangle(const char* name);
95
96 /// Integer nonlinear key type
97 typedef std::uint64_t Key;
98
99 /// Integer nonlinear factor index type
100 typedef std::uint64_t FactorIndex;
101
102 /// The index type for Eigen objects
103 typedef ptrdiff_t DenseIndex;
104
105 /* ************************************************************************* */
106 /**
107 * Helper class that uses templates to select between two types based on
108 * whether TEST_TYPE is const or not.
109 */
110 template<typename TEST_TYPE, typename BASIC_TYPE, typename AS_NON_CONST,
111 typename AS_CONST>
112 struct const_selector {
113 };
114
115 /** Specialization for the non-const version */
116 template<typename BASIC_TYPE, typename AS_NON_CONST, typename AS_CONST>
117 struct const_selector<BASIC_TYPE, BASIC_TYPE, AS_NON_CONST, AS_CONST> {
118 typedef AS_NON_CONST type;
119 };
120
121 /** Specialization for the const version */
122 template<typename BASIC_TYPE, typename AS_NON_CONST, typename AS_CONST>
123 struct const_selector<const BASIC_TYPE, BASIC_TYPE, AS_NON_CONST, AS_CONST> {
124 typedef AS_CONST type;
125 };
126
127 /* ************************************************************************* */
128 /**
129 * Helper struct that encapsulates a value with a default, this is just used
130 * as a member object so you don't have to specify defaults in the class
131 * constructor.
132 */
133 template<typename T, T defaultValue>
134 struct ValueWithDefault {
135 T value;
136
137 /** Default constructor, initialize to default value supplied in template argument */
138 ValueWithDefault() : value(defaultValue) {}
139
140 /** Initialize to the given value */
141 ValueWithDefault(const T& _value) : value(_value) {}
142
143 /** Operator to access the value */
144 T& operator*() { return value; }
145
146 /** Operator to access the value */
147 const T& operator*() const { return value; }
148
149 /** Implicit conversion allows use in if statements for bool type, etc. */
150 operator T() const { return value; }
151 };
152
153 /* ************************************************************************* */
154#ifdef __clang__
155# pragma clang diagnostic push
156# pragma clang diagnostic ignored "-Wunused-private-field" // Clang complains that previousOpenMPThreads is unused in the #else case below
157#endif
158
159 /// An object whose scope defines a block where TBB and OpenMP parallelism are mixed. In such a
160 /// block, we use default threads for TBB, and p/2 threads for OpenMP. If GTSAM is not compiled to
161 /// use both TBB and OpenMP, this has no effect.
162 class TbbOpenMPMixedScope
163 {
164 int previousOpenMPThreads;
165
166 public:
167#if defined GTSAM_USE_TBB && defined GTSAM_USE_EIGEN_MKL_OPENMP
168 TbbOpenMPMixedScope() :
169 previousOpenMPThreads(omp_get_num_threads())
170 {
171 omp_set_num_threads(omp_get_num_procs() / 4);
172 }
173
174 ~TbbOpenMPMixedScope()
175 {
176 omp_set_num_threads(previousOpenMPThreads);
177 }
178#else
179 TbbOpenMPMixedScope() : previousOpenMPThreads(-1) {}
180 ~TbbOpenMPMixedScope() {}
181#endif
182 };
183
184#ifdef __clang__
185# pragma clang diagnostic pop
186#endif
187
188}
189
190/* ************************************************************************* */
191/** An assertion that throws an exception if NDEBUG is not defined and
192* evaluates to an empty statement otherwise. */
193#ifdef NDEBUG
194#define assert_throw(CONDITION, EXCEPTION) ((void)0)
195#else
196#define assert_throw(CONDITION, EXCEPTION) \
197 if (!(CONDITION)) { \
198 throw (EXCEPTION); \
199 }
200#endif
201
202#ifdef _MSC_VER
203
204// Define some common g++ functions and macros we use that MSVC does not have
205
206#if (_MSC_VER < 1800)
207
208#include <cmath>
209namespace std {
210 template<typename T> inline int isfinite(T a) {
211 return (int)std::isfinite(a); }
212 template<typename T> inline int isnan(T a) {
213 return (int)std::isnan(a); }
214 template<typename T> inline int isinf(T a) {
215 return (int)std::isinf(a); }
216}
217
218#endif
219
220#include <cmath>
221#ifndef M_PI
222#define M_PI (3.14159265358979323846)
223#endif
224#ifndef M_PI_2
225#define M_PI_2 (M_PI / 2.0)
226#endif
227#ifndef M_PI_4
228#define M_PI_4 (M_PI / 4.0)
229#endif
230
231#endif
232
233#ifdef min
234#undef min
235#endif
236
237#ifdef max
238#undef max
239#endif
240
241#ifdef ERROR
242#undef ERROR
243#endif
244
245namespace gtsam {
246
247 /// Convenience void_t as we assume C++11, it will not conflict the std one in C++17 as this is in `gtsam::`
248 template<typename ...> using void_t = void;
249
250 /**
251 * A SFINAE trait to mark classes that need special alignment.
252 *
253 * This is required to make std::make_shared and etc respect alignment, which is essential for the Python
254 * wrappers to work properly.
255 *
256 * Explanation
257 * =============
258 * When a GTSAM type is not declared with the type alias `_eigen_aligned_allocator_trait = void`, the first template
259 * will be taken so `needs_eigen_aligned_allocator` will be resolved to `std::false_type`.
260 *
261 * Otherwise, it will resolve to the second template, which will be resolved to `std::true_type`.
262 *
263 * Please refer to `gtsam/base/make_shared.h` for an example.
264 */
265 template<typename, typename = void_t<>>
266 struct needs_eigen_aligned_allocator : std::false_type {
267 };
268 template<typename T>
269 struct needs_eigen_aligned_allocator<T, void_t<typename T::_eigen_aligned_allocator_trait>> : std::true_type {
270 };
271
272}
273
274/**
275 * This marks a GTSAM object to require alignment. With this macro an object will automatically be allocated in aligned
276 * memory when one uses `gtsam::make_shared`. It reduces future misalignment problems that is hard to debug.
277 * See https://eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html for detailed explanation.
278 */
279#define GTSAM_MAKE_ALIGNED_OPERATOR_NEW \
280 EIGEN_MAKE_ALIGNED_OPERATOR_NEW \
281 using _eigen_aligned_allocator_trait = void;
282
283/**
284 * This marks a GTSAM object to require alignment. With this macro an object will automatically be allocated in aligned
285 * memory when one uses `gtsam::make_shared`. It reduces future misalignment problems that is hard to debug.
286 * See https://eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html for detailed explanation.
287 */
288#define GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \
289 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \
290 using _eigen_aligned_allocator_trait = void;
291