| 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 | |
| 91 | namespace 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> |
| 209 | namespace 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 | |
| 245 | namespace 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 | |