HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
platform.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: Apache-2.0
3 // https://github.com/AcademySoftwareFoundation/OpenImageIO
4 
5 
6 /////////////////////////////////////////////////////////////////////////
7 // \file
8 // platform.h is where we put all the platform-specific macros.
9 // Things like:
10 //
11 // * Detecting which compiler is being used.
12 // * Detecting which C++ standard is being used and what features are
13 // available.
14 // * Various helpers that need to be defined differently per compiler,
15 // language version, OS, etc.
16 /////////////////////////////////////////////////////////////////////////
17 
18 // clang-format off
19 
20 #pragma once
21 
22 #include <cassert>
23 #include <cstdlib>
24 #include <type_traits>
25 #include <utility> // std::forward
26 
27 // Make sure all platforms have the explicit sized integer types
28 #ifndef __STDC_LIMIT_MACROS
29 # define __STDC_LIMIT_MACROS /* needed for some defs in stdint.h */
30 #endif
31 #include <cstdint>
32 
33 #if defined(__FreeBSD__)
34 # include <sys/param.h>
35 #endif
36 
37 #ifdef __MINGW32__
38 # include <malloc.h> // for alloca
39 #endif
40 
41 #ifdef _MSC_VER
42 # include <intrin.h>
43 #endif
44 
45 // Avoid min and max being defined for any subsequent include of windows.h
46 #ifdef _WIN32
47 # ifndef NOMINMAX
48 # define NOMINMAX
49 # endif
50 #endif
51 
53 #include <OpenImageIO/export.h>
54 
55 // Detect which C++ standard we're using, and handy macros.
56 // See https://en.cppreference.com/w/cpp/compiler_support
57 //
58 // OIIO_CPLUSPLUS_VERSION : which C++ standard is compiling (14, 17, ...)
59 // OIIO_CONSTEXPR14 :
60 // OIIO_CONSTEXPR17 :
61 // OIIO_CONSTEXPR20 : constexpr for C++ >= the designated version, otherwise
62 // nothing (this is useful for things that can only be
63 // constexpr for particular versions or greater).
64 // OIIO_INLINE_CONSTEXPR : inline constexpr variables, added in C++17. For
65 // older C++, static constexpr.
66 //
67 // Note: oiioversion.h defines OIIO_BUILD_CPP (set to 14, 17, etc.)
68 // reflecting what OIIO itself was *built* with. In contrast,
69 // OIIO_CPLUSPLUS_VERSION defined below will be set to the right number for
70 // the C++ standard being compiled RIGHT NOW. These two things may be the
71 // same when compiling OIIO, but they may not be the same if another
72 // package is compiling against OIIO and using these headers (OIIO may be
73 // C++14 but the client package may be newer, or vice versa -- use these two
74 // symbols to differentiate these cases, when important).
75 #if (__cplusplus >= 202001L)
76 # define OIIO_CPLUSPLUS_VERSION 20
77 # define OIIO_CONSTEXPR17 constexpr
78 # define OIIO_CONSTEXPR20 constexpr
79 # define OIIO_INLINE_CONSTEXPR inline constexpr
80 #elif (__cplusplus >= 201703L)
81 # define OIIO_CPLUSPLUS_VERSION 17
82 # define OIIO_CONSTEXPR17 constexpr
83 # define OIIO_CONSTEXPR20 /* not constexpr before C++20 */
84 # define OIIO_INLINE_CONSTEXPR inline constexpr
85 #elif (__cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1914)
86 # define OIIO_CPLUSPLUS_VERSION 14
87 # define OIIO_CONSTEXPR17 /* not constexpr before C++17 */
88 # define OIIO_CONSTEXPR20 /* not constexpr before C++20 */
89 # define OIIO_INLINE_CONSTEXPR static constexpr
90 #else
91 # error "This version of OIIO is meant to work only with C++14 and above"
92 #endif
93 
94 // DEPRECATED(2.3): use C++14 constexpr
95 #define OIIO_CONSTEXPR14 constexpr
96 
97 // DEPRECATED(1.8): use C++11 constexpr
98 #define OIIO_CONSTEXPR constexpr
99 #define OIIO_CONSTEXPR_OR_CONST constexpr
100 
101 // DEPRECATED(1.8): use C++11 noexcept
102 #define OIIO_NOEXCEPT noexcept
103 
104 
105 // In C++20 (and some compilers before that), __has_cpp_attribute can
106 // test for understand of [[attr]] tests.
107 #ifndef __has_cpp_attribute
108 # define __has_cpp_attribute(x) 0
109 #endif
110 
111 // On gcc & clang, __has_attribute can test for __attribute__((attr))
112 #ifndef __has_attribute
113 # define __has_attribute(x) 0
114 #endif
115 
116 // In C++17 (and some compilers before that), __has_include("blah.h") or
117 // __has_include(<blah.h>) can test for presence of an include file.
118 #ifndef __has_include
119 # define __has_include(x) 0
120 #endif
121 
122 
123 
124 // Detect which compiler and version we're using
125 
126 // Notes:
127 // __GNUC__ is defined for gcc and all clang varieties
128 // __clang__ is defined for all clang varieties (generic and Apple)
129 // __apple_build_version__ is only defined for Apple clang
130 // __INTEL_COMPILER is defined only for icc
131 // __INTEL_LLVM_COMPILER is defined only for icx
132 // _MSC_VER is defined for MSVS compiler (not gcc/clang/icc even on Windows)
133 // _WIN32 is defined on Windows regardless of compiler
134 // __CUDACC__ is defined any time we are compiling a module for Cuda
135 // (both for the host pass and the device pass). "Do this
136 // when using nvcc or clang with ptx target."
137 // __CUDA_ARCH__ is only defined when doing the device pass. "Do this only
138 // for code that will actually run on the GPU."
139 
140 
141 // Define OIIO_GNUC_VERSION to hold an encoded gcc version (e.g. 40802 for
142 // 4.8.2), or 0 if not a GCC release. N.B.: This will be 0 for clang.
143 #if defined(__GNUC__) && !defined(__clang__)
144 # define OIIO_GNUC_VERSION (10000*__GNUC__ + 100*__GNUC_MINOR__ + __GNUC_PATCHLEVEL__)
145 #else
146 # define OIIO_GNUC_VERSION 0
147 #endif
148 
149 // Define OIIO_CLANG_VERSION to hold an encoded generic Clang version (e.g.
150 // 30402 for clang 3.4.2), or 0 if not a generic Clang release.
151 // N.B. This will be 0 for the clang Apple distributes (which has different
152 // version numbers entirely) and for the Intel clang-based compiler.
153 #if defined(__clang__) && !defined(__apple_build_version__) && !defined(__INTEL_LLVM_COMPILER)
154 # define OIIO_CLANG_VERSION (10000*__clang_major__ + 100*__clang_minor__ + __clang_patchlevel__)
155 #else
156 # define OIIO_CLANG_VERSION 0
157 #endif
158 
159 // Define OIIO_APPLE_CLANG_VERSION to hold an encoded Apple Clang version
160 // (e.g. 70002 for clang 7.0.2), or 0 if not an Apple Clang release.
161 #if defined(__clang__) && defined(__apple_build_version__)
162 # if defined(__INTEL_LLVM_COMPILER)
163 # error Not expected for __INTEL_LLVM_COMPILER to be defined with an __apple_build_version__
164  // The classic Intel(r) C++ Compiler on OSX may still define __clang__.
165  // Combine with testing OIIO_INTEL_COMPILER to further differentiate if
166  // needed.
167 # endif
168 # define OIIO_APPLE_CLANG_VERSION (10000*__clang_major__ + 100*__clang_minor__ + __clang_patchlevel__)
169 #else
170 # define OIIO_APPLE_CLANG_VERSION 0
171 #endif
172 
173 // Define OIIO_INTEL_CLASSIC_COMPILER_VERSION to hold an encoded Intel
174 // compiler version (e.g. 1900), or 0 if not an Intel compiler.
175 #if defined(__INTEL_COMPILER)
176 # define OIIO_INTEL_CLASSIC_COMPILER_VERSION __INTEL_COMPILER
177 #else
178 # define OIIO_INTEL_CLASSIC_COMPILER_VERSION 0
179 #endif
180 
181 // DEPRECATED(2.4) phase out OIIO_NON_INTEL_CLANG for OIIO_INTEL_LLVM_COMPILER.
182 // We're keeping the old one for a while for back compatibility.
183 #if !defined(__INTEL_COMPILER) && defined(__clang__)
184 # define OIIO_NON_INTEL_CLANG __clang__
185 #else
186 # define OIIO_NON_INTEL_CLANG 0
187 #endif
188 
189 // Define OIIO_INTEL_LLVM_COMPILER to hold an encoded Intel(r) LLVM Compiler
190 // version (e.g. 20220000), or 0 if not an Intel(r) LLVM Compiler.
191 // Define OIIO_INTEL_CLANG_VERSION to hold the encoded Clang version the
192 // Intel(r) LLVM Compiler is based on (e.g. 140000), or 0 if not an Intel(r)
193 // LLVM compiler.
194 #if defined(__INTEL_LLVM_COMPILER)
195 # define OIIO_INTEL_LLVM_COMPILER __INTEL_LLVM_COMPILER
196 # define OIIO_INTEL_CLANG_VERSION (10000*__clang_major__ + 100*__clang_minor__ + __clang_patchlevel__)
197 #else
198 # define OIIO_INTEL_LLVM_COMPILER 0
199 # define OIIO_INTEL_CLANG_VERSION 0
200 #endif
201 
202 // Define OIIO_ANY_CLANG to 0 or 1 to indicate if any Clang based compiler is
203 // in use.
204 #if defined(__clang__)
205 # define OIIO_ANY_CLANG 1
206 #else
207 # define OIIO_ANY_CLANG 0
208 #endif
209 
210 // Tests for MSVS versions, always 0 if not MSVS at all.
211 #if defined(_MSC_VER)
212 # define OIIO_MSVS_VERSION _MSC_VER
213 # define OIIO_MSVS_AT_LEAST_2013 (_MSC_VER >= 1800)
214 # define OIIO_MSVS_BEFORE_2013 (_MSC_VER < 1800)
215 # define OIIO_MSVS_AT_LEAST_2015 (_MSC_VER >= 1900)
216 # define OIIO_MSVS_BEFORE_2015 (_MSC_VER < 1900)
217 # define OIIO_MSVS_AT_LEAST_2017 (_MSC_VER >= 1910)
218 # define OIIO_MSVS_BEFORE_2017 (_MSC_VER < 1910)
219 # define OIIO_MSVS_AT_LEAST_2019 (_MSC_VER >= 1920)
220 # define OIIO_MSVS_BEFORE_2019 (_MSC_VER < 1920)
221 # define OIIO_MSVS_AT_LEAST_2022 (_MSC_VER >= 1930)
222 # define OIIO_MSVS_BEFORE_2022 (_MSC_VER < 1930)
223 # if OIIO_MSVS_BEFORE_2017
224 # error "This version of OIIO is meant to work only with Visual Studio 2017 or later"
225 # endif
226 #else
227 # define OIIO_MSVS_VERSION 0
228 # define OIIO_MSVS_AT_LEAST_2013 0
229 # define OIIO_MSVS_BEFORE_2013 0
230 # define OIIO_MSVS_AT_LEAST_2015 0
231 # define OIIO_MSVS_BEFORE_2015 0
232 # define OIIO_MSVS_AT_LEAST_2017 0
233 # define OIIO_MSVS_BEFORE_2017 0
234 # define OIIO_MSVS_AT_LEAST_2019 0
235 # define OIIO_MSVS_BEFORE_2019 0
236 # define OIIO_MSVS_AT_LEAST_2022 0
237 # define OIIO_MSVS_BEFORE_2022 0
238 #endif
239 
240 
241 // Pragma control
242 //
243 // OIIO_PRAGMA(x) make a pragma for *unquoted* x
244 // OIIO_PRAGMA_WARNING_PUSH/POP -- push/pop warning state
245 // OIIO_VISIBILITY_PUSH/POP -- push/pop symbol visibility state
246 // OIIO_GCC_PRAGMA(x) -- pragma on gcc/clang/icc only
247 // OIIO_CLANG_PRAGMA(x) -- pragma on clang only (not gcc or icc)
248 // OIIO_MSVS_PRAGMA(x) -- pragma on MSVS only
249 // OIIO_INTEL_PRAGMA(x) -- pragma on Intel icc compiler only
250 // OIIO_INTEL_LLVM_PRAGMA(x) -- pragma on Intel icx compiler only
251 
252 // Generic pragma definition
253 #if defined(_MSC_VER)
254  // Of course MS does it in a quirky way
255  #define OIIO_PRAGMA(UnQuotedPragma) __pragma(UnQuotedPragma)
256 #else
257  // All other compilers seem to support C99 _Pragma
258  #define OIIO_PRAGMA(UnQuotedPragma) _Pragma(#UnQuotedPragma)
259 #endif
260 
261 #if defined(__GNUC__) /* gcc, clang, icc, icx */
262 # define OIIO_PRAGMA_WARNING_PUSH OIIO_PRAGMA(GCC diagnostic push)
263 # define OIIO_PRAGMA_WARNING_POP OIIO_PRAGMA(GCC diagnostic pop)
264 # define OIIO_PRAGMA_VISIBILITY_PUSH OIIO_PRAGMA(GCC visibility push(default))
265 # define OIIO_PRAGMA_VISIBILITY_POP OIIO_PRAGMA(GCC visibility pop)
266 # define OIIO_GCC_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
267 # if defined(__clang__)
268 # define OIIO_CLANG_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
269 # define OIIO_GCC_ONLY_PRAGMA(UnQuotedPragma)
270 # else
271 # define OIIO_CLANG_PRAGMA(UnQuotedPragma)
272 # define OIIO_GCC_ONLY_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
273 # endif
274 # if defined(__INTEL_COMPILER)
275 # define OIIO_INTEL_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
276 # else
277 # define OIIO_INTEL_PRAGMA(UnQuotedPragma)
278 # endif
279 # if defined(__INTEL_LLVM_COMPILER)
280 # define OIIO_INTEL_LLVM_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
281 # else
282 # define OIIO_INTEL_LLVM_PRAGMA(UnQuotedPragma)
283 # endif
284 # define OIIO_MSVS_PRAGMA(UnQuotedPragma)
285 #elif defined(_MSC_VER)
286 # define OIIO_PRAGMA_WARNING_PUSH __pragma(warning(push))
287 # define OIIO_PRAGMA_WARNING_POP __pragma(warning(pop))
288 # define OIIO_PRAGMA_VISIBILITY_PUSH /* N/A on MSVS */
289 # define OIIO_PRAGMA_VISIBILITY_POP /* N/A on MSVS */
290 # define OIIO_GCC_PRAGMA(UnQuotedPragma)
291 # define OIIO_GCC_ONLY_PRAGMA(UnQuotedPragma)
292 # define OIIO_CLANG_PRAGMA(UnQuotedPragma)
293 # define OIIO_INTEL_PRAGMA(UnQuotedPragma)
294 # define OIIO_INTEL_LLVM_PRAGMA(UnQuotedPragma)
295 # define OIIO_MSVS_PRAGMA(UnQuotedPragma) OIIO_PRAGMA(UnQuotedPragma)
296 #else
297 # define OIIO_PRAGMA_WARNING_PUSH
298 # define OIIO_PRAGMA_WARNING_POP
299 # define OIIO_PRAGMA_VISIBILITY_PUSH
300 # define OIIO_PRAGMA_VISIBILITY_POP
301 # define OIIO_GCC_PRAGMA(UnQuotedPragma)
302 # define OIIO_GCC_ONLY_PRAGMA(UnQuotedPragma)
303 # define OIIO_CLANG_PRAGMA(UnQuotedPragma)
304 # define OIIO_INTEL_PRAGMA(UnQuotedPragma)
305 # define OIIO_INTEL_LLVM_PRAGMA(UnQuotedPragma)
306 # define OIIO_MSVS_PRAGMA(UnQuotedPragma)
307 #endif
308 
309 
310 
311 /// OIIO_ALLOCA is used to allocate smallish amount of memory on the stack,
312 /// equivalent of C99 type var_name[size].
313 ///
314 /// NOTE: in a debug build, this will assert for allocations >= 1MB, which
315 /// is much too big. Hopefully this will keep us from abusing alloca and
316 /// having stack overflows. The rule of thumb is that it's ok to use alloca
317 /// for small things of bounded size (like, one float per channel), but
318 /// not for anything that could be arbitrarily big (like a full scanline or
319 /// image, because sooner or later somebody will give you an image big
320 /// enough to cause trouble). Consider using the OIIO_ALLOCATE_STACK_OR_HEAP
321 /// idiom rather than a direct OIIO_ALLOCA if you aren't sure the item will
322 /// be small.
323 #if defined(__GNUC__)
324 # define OIIO_ALLOCA(type, size) (assert(size < (1<<20)), (size) != 0 ? ((type*)__builtin_alloca((size) * sizeof(type))) : nullptr)
325 #else
326 # define OIIO_ALLOCA(type, size) (assert(size < (1<<20)), (size) != 0 ? ((type*)alloca((size) * sizeof(type))) : nullptr)
327 #endif
328 
329 /// Deprecated (for namespace pollution reasons)
330 #define ALLOCA(type, size) OIIO_ALLOCA(type, size)
331 
332 
333 /// Try to allocate T* var to point to T[size] elements of temporary storage
334 /// that will automatically free when the local scope is exited. Allocate
335 /// the space on the stack with alloca if it's small, but if it's big (> 64
336 /// KB), allocate on the heap with a new[], stored as a std::unique_ptr. In
337 /// both cases, the memory will be freed automatically upon exit of scope.
338 /// That threshold is big enough for one scanline of a 4096 x 4 channel x
339 /// float image, or one 64x64 tile of a 4xfloat image.
340 #define OIIO_ALLOCATE_STACK_OR_HEAP(var, T, size) \
341  size_t var##___size = size_t(size); \
342  std::unique_ptr<T[]> var##___heap; \
343  if (var##___size * sizeof(T) <= (1 << 16)) { \
344  var = OIIO_ALLOCA(T, var##___size); \
345  } else { \
346  var##___heap.reset(new T[var##___size]); \
347  var = var##___heap.get(); \
348  }
349 
350 
351 // Define a macro that can be used for memory alignment.
352 // This macro is mostly obsolete and C++11 alignas() should be preferred
353 // for new code.
354 #if defined(__GNUC__) || __has_attribute(aligned)
355 # define OIIO_ALIGN(size) __attribute__((aligned(size)))
356 #elif defined(_MSC_VER)
357 # define OIIO_ALIGN(size) __declspec(align(size))
358 #elif defined(__INTEL_COMPILER)
359 # define OIIO_ALIGN(size) __declspec(align((size)))
360 #else
361 # define OIIO_ALIGN(size) alignas(size)
362 #endif
363 
364 // Cache line size is 64 on all modern x86 CPUs. If this changes or we
365 // anticipate ports to other architectures, we'll need to change this.
366 #define OIIO_CACHE_LINE_SIZE 64
367 
368 // Align the next declaration to be on its own cache line
369 #define OIIO_CACHE_ALIGN OIIO_ALIGN(OIIO_CACHE_LINE_SIZE)
370 
371 
372 
373 // gcc defines a special intrinsic to use in conditionals that can speed
374 // up extremely performance-critical spots if the conditional usually
375 // (or rarely) is true. You use it by replacing
376 // if (x) ...
377 // with
378 // if (OIIO_LIKELY(x)) ... // if you think x will usually be true
379 // or
380 // if (OIIO_UNLIKELY(x)) ... // if you think x will rarely be true
381 // Caveat: Programmers are notoriously bad at guessing this, so it
382 // should be used only with thorough benchmarking.
383 #if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
384 # define OIIO_LIKELY(x) (__builtin_expect(bool(x), true))
385 # define OIIO_UNLIKELY(x) (__builtin_expect(bool(x), false))
386 #else
387 # define OIIO_LIKELY(x) (x)
388 # define OIIO_UNLIKELY(x) (x)
389 #endif
390 
391 
392 // OIIO_FORCELINE is a function attribute that attempts to make the function
393 // always inline. On many compilers regular 'inline' is only advisory. Put
394 // this attribute before the function return type, just like you would use
395 // 'inline'.
396 #if defined(__CUDACC__)
397 # define OIIO_FORCEINLINE __inline__
398 #elif defined(__GNUC__) || defined(__clang__) || __has_attribute(always_inline)
399 # define OIIO_FORCEINLINE inline __attribute__((always_inline))
400 #elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
401 # define OIIO_FORCEINLINE __forceinline
402 #else
403 # define OIIO_FORCEINLINE inline
404 #endif
405 
406 // OIIO_PURE_FUNC is a function attribute that assures the compiler that the
407 // function does not write to any non-local memory other than its return
408 // value and has no side effects. This can enable additional compiler
409 // optimizations by knowing that calling the function cannot possibly alter
410 // any other memory. This declaration goes after the function declaration:
411 // int blah (int arg) OIIO_PURE_FUNC;
412 #if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) || __has_attribute(pure)
413 # define OIIO_PURE_FUNC __attribute__((pure))
414 #elif defined(_MSC_VER)
415 # define OIIO_PURE_FUNC /* seems not supported by MSVS */
416 #else
417 # define OIIO_PURE_FUNC
418 #endif
419 
420 // OIIO_CONST_FUNC is a function attribute that assures the compiler that
421 // the function does not examine (read) any values except for its arguments,
422 // does not write any non-local memory other than its return value, and has
423 // no side effects. This is even more strict than 'pure', and allows even
424 // more optimizations (such as eliminating multiple calls to the function
425 // that have the exact same argument values).
426 #if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) || __has_attribute(const)
427 # define OIIO_CONST_FUNC __attribute__((const))
428 #elif defined(_MSC_VER)
429 # define OIIO_CONST_FUNC /* seems not supported by MSVS */
430 #else
431 # define OIIO_CONST_FUNC
432 #endif
433 
434 // OIIO_MAYBE_UNUSED is a function or variable attribute that assures the
435 // compiler that it's fine for the item to appear to be unused.
436 #if OIIO_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(maybe_unused)
437 # define OIIO_MAYBE_UNUSED [[maybe_unused]]
438 #elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) || __has_attribute(unused)
439 # define OIIO_MAYBE_UNUSED __attribute__((unused))
440 #else
441 # define OIIO_MAYBE_UNUSED
442 #endif
443 
444 // DEPRECATED(1.9) name:
445 #define OIIO_UNUSED_OK OIIO_MAYBE_UNUSED
446 
447 // OIIO_RESTRICT is a parameter attribute that indicates a promise that the
448 // parameter definitely will not alias any other parameters in such a way
449 // that creates a data dependency. Use with caution!
450 #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(__INTEL_COMPILER)
451 # define OIIO_RESTRICT __restrict
452 #else
453 # define OIIO_RESTRICT
454 #endif
455 
456 
457 // OIIO_DEPRECATED before a function declaration marks it as deprecated in
458 // a way that will generate compile warnings if it is called.
459 #if OIIO_CPLUSPLUS_VERSION >= 14 || __has_cpp_attribute(deprecated)
460 # define OIIO_DEPRECATED(msg) [[deprecated(msg)]]
461 #elif defined(__GNUC__) || defined(__clang__) || __has_attribute(deprecated)
462 # define OIIO_DEPRECATED(msg) __attribute__((deprecated(msg)))
463 #elif defined(_MSC_VER)
464 # define OIIO_DEPRECATED(msg) __declspec(deprecated(msg))
465 #else
466 # define OIIO_DEPRECATED(msg)
467 #endif
468 
469 
470 // OIIO_FALLTHROUGH at the end of a `case` label's statements documents that
471 // the switch statement case is intentionally falling through to the code
472 // for the next case.
473 #if OIIO_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(fallthrough)
474 # define OIIO_FALLTHROUGH [[fallthrough]]
475 #else
476 # define OIIO_FALLTHROUGH
477 #endif
478 
479 
480 // OIIO_NODISCARD following a function declaration documents that the
481 // function's return value should never be ignored.
482 #if OIIO_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(nodiscard)
483 # define OIIO_NODISCARD [[nodiscard]]
484 #else
485 # define OIIO_NODISCARD
486 #endif
487 
488 
489 // OIIO_NO_SANITIZE_ADDRESS can be used to mark a function that you don't
490 // want address sanitizer to catch. Only use this if you know there are
491 // false positives that you can't easily get rid of.
492 // This should work for any clang >= 3.3 and gcc >= 4.8, which are
493 // guaranteed by our minimum requirements.
494 #if defined(__clang__) || (OIIO_GNUC_VERSION > 90000 && !defined(__INTEL_COMPILER)) \
495  || __has_attribute(no_sanitize_address)
496 # define OIIO_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
497 #else
498 # define OIIO_NO_SANITIZE_ADDRESS
499 #endif
500 
501 
502 // OIIO_NO_SANITIZE_UNDEFINED can be used to mark a function that you don't
503 // want undefined behavior sanitizer to catch. Only use this if you know there
504 // are false positives that you can't easily get rid of.
505 #if defined(__clang__) || (OIIO_GNUC_VERSION > 90000 && !defined(__INTEL_COMPILER)) \
506  || __has_attribute(no_sanitize)
507 # define OIIO_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
508 #else
509 # define OIIO_NO_SANITIZE_UNDEFINED
510 #endif
511 
512 
513 // OIIO_RETURNS_NONNULL following a function declaration of a function
514 // indicates that the pointer returned by the function is guaranteed to
515 // never be nullptr.
516 #if defined(__clang__) || defined(__GNUC__) || __has_attribute(returns_nonnull)
517 # define OIIO_RETURNS_NONNULL __attribute__((returns_nonnull))
518 #else
519 # define OIIO_RETURNS_NONNULL
520 #endif
521 
522 
523 // OIIO_HOSTDEVICE is used before a function declaration to supply the
524 // function decorators needed when compiling for CUDA devices.
525 #ifdef __CUDACC__
526 # define OIIO_HOSTDEVICE __host__ __device__
527 # define OIIO_DEVICE __device__
528 #else
529 # define OIIO_HOSTDEVICE
530 # define OIIO_DEVICE
531 #endif
532 
533 
534 // OIIO_DEVICE_CONSTEXPR is like OIIO_HOSTDEVICE, but it's `constexpr` only on
535 // the Cuda device side, and merely inline (not constexpr) on the host side.
536 #ifdef __CUDA_ARCH__
537 # define OIIO_DEVICE_CONSTEXPR __device__ constexpr
538 #else
539 # define OIIO_DEVICE_CONSTEXPR /*__host__*/ inline
540 #endif
541 
542 
543 
544 // OIIO_PRETTY_FUNCTION gives a text string of the current function
545 // declaration.
546 #if defined(__PRETTY_FUNCTION__)
547 # define OIIO_PRETTY_FUNCTION __PRETTY_FUNCTION__ /* gcc, clang */
548 #elif defined(__FUNCSIG__)
549 # define OIIO_PRETTY_FUNCTION __FUNCSIG__ /* MS gotta be different */
550 #else
551 # define OIIO_PRETTY_FUNCTION __FUNCTION__
552 #endif
553 
554 
555 
557 
558 /// Class for describing endianness. Test for endianness as
559 /// `if (endian::native == endian::little)` or
560 /// `if (endian::native == endian::big)`.
561 /// This uses the same semantics as C++20's std::endian.
562 enum class endian {
563 #ifdef _WIN32 /* All Windows platforms are little endian */
564  little = 0,
565  big = 1,
566  native = little
567 #else /* gcc, clang, icc all define these macros */
568  little = __ORDER_LITTLE_ENDIAN__,
569  big = __ORDER_BIG_ENDIAN__,
570  native = __BYTE_ORDER__
571 #endif
572 };
573 
574 
575 /// Return true if the architecture we are running on is little endian.
576 OIIO_FORCEINLINE constexpr bool
577 littleendian(void) noexcept
578 {
579  return endian::native == endian::little;
580 }
581 
582 
583 /// Return true if the architecture we are running on is big endian.
584 OIIO_FORCEINLINE constexpr bool
585 bigendian(void) noexcept
586 {
587  return endian::native == endian::big;
588 }
589 
590 
591 
592 /// Retrieve cpuid flags into 'info'.
593 inline void cpuid (int info[4], int infoType, int extra)
594 {
595  // Implementation cribbed from Halide (http://halide-lang.org), which
596  // cribbed it from ISPC (https://github.com/ispc/ispc).
597 #if (defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__))
598 # ifdef _MSC_VER
599  __cpuidex(info, infoType, extra);
600 # elif defined(__x86_64__)
601  __asm__ __volatile__ (
602  "cpuid \n\t"
603  : "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3])
604  : "0" (infoType), "2" (extra));
605 # else
606  __asm__ __volatile__ (
607  "mov{l}\t{%%}ebx, %1 \n\t"
608  "cpuid \n\t"
609  "xchg{l}\t{%%}ebx, %1 \n\t"
610  : "=a" (info[0]), "=r" (info[1]), "=c" (info[2]), "=d" (info[3])
611  : "0" (infoType), "2" (extra));
612 # endif
613 #else
614  info[0] = 0; info[1] = 0; info[2] = 0; info[3] = 0;
615 #endif
616 }
617 
618 
619 inline bool cpu_has_sse2 () {int i[4]; cpuid(i,1,0); return (i[3] & (1<<26)) != 0; }
620 inline bool cpu_has_sse3 () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<0)) != 0; }
621 inline bool cpu_has_ssse3 () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<9)) != 0; }
622 inline bool cpu_has_fma () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<12)) != 0; }
623 inline bool cpu_has_sse41 () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<19)) != 0; }
624 inline bool cpu_has_sse42 () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<20)) != 0; }
625 inline bool cpu_has_popcnt() {int i[4]; cpuid(i,1,0); return (i[2] & (1<<23)) != 0; }
626 inline bool cpu_has_avx () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<28)) != 0; }
627 inline bool cpu_has_f16c () {int i[4]; cpuid(i,1,0); return (i[2] & (1<<29)) != 0; }
628 inline bool cpu_has_rdrand() {int i[4]; cpuid(i,1,0); return (i[2] & (1<<30)) != 0; }
629 inline bool cpu_has_avx2 () {int i[4]; cpuid(i,7,0); return (i[1] & (1<<5)) != 0; }
630 inline bool cpu_has_avx512f() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<16)) != 0; }
631 inline bool cpu_has_avx512dq() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<17)) != 0; }
632 inline bool cpu_has_avx512ifma() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<21)) != 0; }
633 inline bool cpu_has_avx512pf() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<26)) != 0; }
634 inline bool cpu_has_avx512er() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<27)) != 0; }
635 inline bool cpu_has_avx512cd() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<28)) != 0; }
636 inline bool cpu_has_avx512bw() {int i[4]; cpuid(i,7,0); return (i[1] & (1<<30)) != 0; }
637 inline bool cpu_has_avx512vl() {int i[4]; cpuid(i,7,0); return (i[1] & (0x80000000 /*1<<31*/)) != 0; }
638 
639 // portable aligned malloc
640 OIIO_API void* aligned_malloc(std::size_t size, std::size_t align);
641 OIIO_API void aligned_free(void* ptr);
642 
643 // basic wrappers to new/delete over-aligned types since this isn't guaranteed to be supported until C++17
644 template <typename T, class... Args>
645 inline T* aligned_new(Args&&... args) {
646  static_assert(alignof(T) > alignof(void*), "Type doesn't seem to be over-aligned, aligned_new is not required");
647  void* ptr = aligned_malloc(sizeof(T), alignof(T));
649  OIIO_INTEL_PRAGMA(warning disable 873)
650  return ptr ? new (ptr) T(std::forward<Args>(args)...) : nullptr;
652 }
653 
654 template <typename T>
655 inline void aligned_delete(T* t) {
656  if (t) {
657  t->~T();
658  aligned_free(t);
659  }
660 }
661 
662 
663 
664 #if OIIO_CPLUSPLUS_VERSION >= 14
665  using std::enable_if_t; // Use C++14 std::enable_if_t
666 #else
667  // Define enable_if_t for C++11
668  template <bool B, class T = void>
670 #endif
671 
672 // An enable_if helper to be used in template parameters which results in
673 // much shorter symbols: https://godbolt.org/z/sWw4vP
674 // Borrowed from fmtlib.
675 #ifndef OIIO_ENABLE_IF
676 # define OIIO_ENABLE_IF(...) OIIO::enable_if_t<(__VA_ARGS__), int> = 0
677 #endif
678 
type
Definition: core.h:556
bool cpu_has_sse42()
Definition: platform.h:624
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
bool cpu_has_avx512ifma()
Definition: platform.h:632
void aligned_delete(T *t)
Definition: platform.h:655
#define OIIO_FORCEINLINE
Definition: platform.h:403
bool cpu_has_avx()
Definition: platform.h:626
bool cpu_has_avx512cd()
Definition: platform.h:635
OIIO_FORCEINLINE constexpr bool bigendian(void) noexcept
Return true if the architecture we are running on is big endian.
Definition: platform.h:585
bool cpu_has_avx2()
Definition: platform.h:629
bool cpu_has_fma()
Definition: platform.h:622
#define OIIO_INTEL_PRAGMA(UnQuotedPragma)
Definition: platform.h:304
#define OIIO_PRAGMA_WARNING_PUSH
Definition: platform.h:297
bool cpu_has_sse2()
Definition: platform.h:619
OIIO_API void aligned_free(void *ptr)
bool cpu_has_sse3()
Definition: platform.h:620
#define OIIO_PRAGMA_WARNING_POP
Definition: platform.h:298
typename std::enable_if< B, T >::type enable_if_t
Definition: platform.h:669
bool cpu_has_avx512pf()
Definition: platform.h:633
bool cpu_has_avx512vl()
Definition: platform.h:637
OIIO_API void * aligned_malloc(std::size_t size, std::size_t align)
bool cpu_has_avx512bw()
Definition: platform.h:636
void cpuid(int info[4], int infoType, int extra)
Retrieve cpuid flags into 'info'.
Definition: platform.h:593
GLdouble t
Definition: glad.h:2397
bool cpu_has_rdrand()
Definition: platform.h:628
GLsizeiptr size
Definition: glcorearb.h:664
bool cpu_has_f16c()
Definition: platform.h:627
endian
Definition: platform.h:562
auto ptr(T p) -> const void *
Definition: format.h:4331
OIIO_FORCEINLINE constexpr bool littleendian(void) noexcept
Return true if the architecture we are running on is little endian.
Definition: platform.h:577
**If you just want to fire and args
Definition: thread.h:618
bool cpu_has_avx512er()
Definition: platform.h:634
bool cpu_has_avx512dq()
Definition: platform.h:631
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:127
bool cpu_has_avx512f()
Definition: platform.h:630
bool cpu_has_popcnt()
Definition: platform.h:625
bool cpu_has_ssse3()
Definition: platform.h:621
bool cpu_has_sse41()
Definition: platform.h:623
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:126
#define OIIO_API
Definition: export.h:65
T * aligned_new(Args &&...args)
Definition: platform.h:645