1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5 
6 /*!
7  *
8  * \file AxomMacros.hpp
9  *
10  * \brief Contains several useful macros for the axom project
11  *
12  */
13 
14 #ifndef AXOM_MACROS_HPP_
15 #define AXOM_MACROS_HPP_
16 
17 #include "axom/config.hpp"
18 #include <cassert>  // for assert()
19 
20 /*!
21  * \def AXOM_DEVICE
22  * \def AXOM_HOST_DEVICE
23  *
24  * \brief CUDA host/device macros for decorating functions/lambdas
25  *
26  * \note These will expand to the corresponding CUDA decorations when
27  *  compiled with -DAXOM_USE_CUDA
28  */
29 #if defined(__CUDACC__)
30   #define AXOM_DEVICE __device__
31   #define AXOM_HOST_DEVICE __host__ __device__
32   #define AXOM_HOST __host__
33 #else
34   #define AXOM_DEVICE
35   #define AXOM_HOST_DEVICE
36   #define AXOM_HOST
37 #endif
38 
39 /*
40  * \def AXOM_STRINGIFY
41  *
42  * \brief Helper Macro to specify strings inside pragmas.
43  */
44 #define AXOM_STRINGIFY(x) AXOM_DO_STRINGIFY(x)
45 #define AXOM_DO_STRINGIFY(x) #x
46 
47 /*
48  * \def AXOM_PRAGMA
49  *
50  * \brief Macro used to specify pragma directive
51  */
52 #ifdef _WIN32
53   #define AXOM_PRAGMA(x) __pragma(x)
54 #else
55   #define AXOM_PRAGMA(x) _Pragma(AXOM_STRINGIFY(x))
56 #endif
57 
58 /*
59  * \def AXOM_SUPPRESS_HD_WARN
60  *
61  * \brief Macro used to silence __host__ __device__ compiler warnings
62  *  when calling __host__ function from __host__ __device__ function.
63  */
64 #if defined(__CUDACC__)
65   #define AXOM_SUPPRESS_HD_WARN AXOM_PRAGMA(nv_exec_check_disable)
66 #else
67   #define AXOM_SUPPRESS_HD_WARN
68 #endif
69 
70 /*!
71  * \def AXOM_LAMBDA
72  *
73  * \brief Convenience macro used for lambda capture by value.
74  * \note When CUDA is used, the macro always expands to a host/device lambda.
75  *
76  * \warning When compiling with CUDA, host/device lambdas incur a significant
77  *  penalty on the CPU code. The way NVCC implements host/device lambdas
78  *  prevents the compiler from proper in-lining them. When CUDA is enabled use
79  *  the parallel_gpu execution policy or opt to turn off CUDA if the application
80  *  is making more use of the parallel_cpu and serial execution policies.
81  */
82 #ifdef AXOM_USE_CUDA
83   #define AXOM_LAMBDA [=] AXOM_HOST_DEVICE
84   #define AXOM_DEVICE_LAMBDA [=] AXOM_DEVICE
85   #define AXOM_HOST_LAMBDA [=] AXOM_HOST
86 #else
87   #define AXOM_LAMBDA [=]
88   #define AXOM_DEVICE_LAMBDA [=]
89   #define AXOM_HOST_LAMBDA [=]
90 #endif
91 
92 /*!
93  * \def AXOM_CUDA_TEST
94  *
95  * \brief Convenience macro used for a gtest that uses cuda.
96  */
97 #if defined(AXOM_USE_CUDA)
98   #define AXOM_CUDA_TEST(X, Y)         \
99     static void cuda_test_##X##Y();    \
100     TEST(X, Y) { cuda_test_##X##Y(); } \
101     static void cuda_test_##X##Y()
102 #else
103   #define AXOM_CUDA_TEST(X, Y) TEST(X, Y)
104 #endif
105 
106 /*!
107  * \def AXOM_DEVICE_CODE
108  *
109  * \brief Convenience macro used for kernel code
110  */
111 #if defined(__CUDA_ARCH__)
112   #define AXOM_DEVICE_CODE
113 #endif
114 
115 /*!
116  *
117  * \def AXOM_UNUSED_PARAM(x)
118  * \brief Macro used to silence compiler warnings in methods with unused arguments.
119  * \note The intent is to use this macro in the function signature. For example:
120  * \code
121  *
122  *  void my_function(int x, int AXOM_UNUSED_PARAM(y))
123  *  {
124  *    // my implementation
125  *  }
126  *
127  * \endcode
128  */
129 #define AXOM_UNUSED_PARAM(x)
130 
131 /*!
132  *
133  * \def AXOM_STATIC_ASSERT(cond)
134  * \def AXOM_STATIC_ASSERT_MSG(cond, MSG)
135  *
136  * \brief This macro wraps the compile time static_assert functionality
137  *  so you don't have to provide a message.
138  */
139 #define AXOM_STATIC_ASSERT(cond) static_assert(cond, #cond)
140 #define AXOM_STATIC_ASSERT_MSG(cond, MSG) static_assert(cond, MSG)
141 
142 /*!
143  *
144  * \def AXOM_UNUSED_VAR(x)
145  * \brief Macro used to silence compiler warnings about variables
146  *        that are defined but not used.
147  * \note The intent is to use this macro for variables that are only used
148  *       within compiler defines (e.g. in debug assertions). For example:
149  * \code
150  *
151  *  double myVar = ...
152  *  AXOM_UNUSED_VAR(myVar);
153  *
154  *  // code emits the following warning in release builds
155  *  // if extra warnings are enabled and this macro is not called
156  *  // warning: unused variable 'myVar' [-Wunused-variable]
157  *
158  *  SLIC_ASSERT(myVar > 0)
159  *
160  * \endcode
161  */
162 #define AXOM_UNUSED_VAR(_x) static_cast<void>(_x)
163 
164 /*!
165  * \def AXOM_DEBUG_PARAM(x)
166  * \brief Macro used to silence compiler warnings about parameters
167  *        that are only used when AXOM_DEBUG is defined
168  * \note Default values are ok
169  * \code
170  *
171  *  void my_function(int x, int AXOM_DEBUG_PARAM(y))
172  *  {
173  *    // my implementation
174  *    SLIC_ASSERT(y > 0)
175  *  }
176  *
177  * \endcode
178  */
179 #ifdef AXOM_DEBUG
180   #define AXOM_DEBUG_PARAM(_x) _x
181 #else
182   #define AXOM_DEBUG_PARAM(_x)
183 #endif
184 
185 /*!
186  * \def DISABLE_DEFAULT_CTOR(className)
187  * \brief Macro to disable default constructor for the given class.
188  * \note This macro should only be used within the private section of a class,
189  *  as indicated in the example below.
190  *
191  * \code
192  *
193  *   class Foo
194  *   {
195  *   public:
196  *
197  *       // Public methods here
198  *
199  *   private:
200  *      DISABLE_DEFAULT_CTOR(Foo);
201  *   };
202  *
203  * \endcode
204  */
205 #define DISABLE_DEFAULT_CTOR(className) className() = delete
206 
207 /*!
208  * \def DISABLE_COPY_AND_ASSIGNMENT(className)
209  * \brief Macro to disable copy and assignment operations for the given class.
210  * \note This macro should only be used within the private section of a class,
211  *  as indicated in the example below.
212  *
213  * \code
214  *
215  *   class Foo
216  *   {
217  *   public:
218  *      Foo();
219  *      ~Foo();
220  *
221  *       // Other methods here
222  *
223  *   private:
224  *      DISABLE_COPY_AND_ASSIGNMENT(Foo);
225  *   };
226  *
227  * \endcode
228  */
229 #define DISABLE_COPY_AND_ASSIGNMENT(className) \
230   className(const className&) = delete;        \
231   className& operator=(const className&) = delete
232 
233 /*!
234  * \def DISABLE_MOVE_AND_ASSIGNMENT(className)
235  * \brief Macro to disable move constructor and move assignment operations for
236  * the given class.
237  * \note This macro should only be used within the private section of a class,
238  *  as indicated in the example below.
239  *
240  * \code
241  *
242  *   class Foo
243  *   {
244  *   public:
245  *      Foo();
246  *      ~Foo();
247  *
248  *       // Other methods here
249  *
250  *   private:
251  *      DISABLE_MOVE_AND_ASSIGNMENT(Foo);
252  *   };
253  *
254  * \endcode
255  */
256 #define DISABLE_MOVE_AND_ASSIGNMENT(className) \
257   className(className&&) = delete;             \
258   className& operator=(className&&) = delete
259 
260 #endif /* AXOM_MACROS_HPP_ */
261