1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef PATH_MATH_COMPILER_H
18 #define PATH_MATH_COMPILER_H
19 
20 #include <type_traits>
21 
22 #if defined (WIN32)
23 
24 #ifdef max
25 #undef max
26 #endif
27 
28 #ifdef min
29 #undef min
30 #endif
31 
32 #ifdef far
33 #undef far
34 #endif
35 
36 #ifdef near
37 #undef near
38 #endif
39 
40 #endif
41 
42 // compatibility with non-clang compilers...
43 #ifndef __has_attribute
44 #define __has_attribute(x) 0
45 #endif
46 #ifndef __has_builtin
47 #define __has_builtin(x) 0
48 #endif
49 
50 #if __has_builtin(__builtin_expect)
51 #   ifdef __cplusplus
52 #      define MATH_LIKELY( exp )    (__builtin_expect( !!(exp), true ))
53 #      define MATH_UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
54 #   else
55 #      define MATH_LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
56 #      define MATH_UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
57 #   endif
58 #else
59 #   define MATH_LIKELY( exp )    (exp)
60 #   define MATH_UNLIKELY( exp )  (exp)
61 #endif
62 
63 #if __has_attribute(unused)
64 #   define MATH_UNUSED __attribute__((unused))
65 #else
66 #   define MATH_UNUSED
67 #endif
68 
69 #if __has_attribute(pure)
70 #   define MATH_PURE __attribute__((pure))
71 #else
72 #   define MATH_PURE
73 #endif
74 
75 #ifdef _MSC_VER
76 #   define MATH_EMPTY_BASES __declspec(empty_bases)
77 
78 // MSVC does not support loop unrolling hints
79 #   define MATH_NOUNROLL
80 
81 // Sadly, MSVC does not support __builtin_constant_p
82 #   ifndef MAKE_CONSTEXPR
83 #       define MAKE_CONSTEXPR(e) (e)
84 #   endif
85 
86 // About value initialization, the C++ standard says:
87 //   if T is a class type with a default constructor that is neither user-provided nor deleted
88 //   (that is, it may be a class with an implicitly-defined or defaulted default constructor),
89 //   the object is zero-initialized and then it is default-initialized
90 //   if it has a non-trivial default constructor;
91 // Unfortunately, MSVC always calls the default constructor, even if it is trivial, which
92 // breaks constexpr-ness. To workaround this, we're always zero-initializing TVecN<>
93 #   define MATH_CONSTEXPR_INIT {}
94 #   define MATH_DEFAULT_CTOR {}
95 #   define MATH_DEFAULT_CTOR_CONSTEXPR constexpr
96 #   define CONSTEXPR_IF_NOT_MSVC // when declared constexpr, msvc fails with
97                                  // "failure was caused by cast of object of dynamic type"
98 
99 #else // _MSC_VER
100 
101 #   define MATH_EMPTY_BASES
102 // C++11 allows pragmas to be specified as part of defines using the _Pragma syntax.
103 #   define MATH_NOUNROLL _Pragma("nounroll")
104 
105 #   ifndef MAKE_CONSTEXPR
106 #       define MAKE_CONSTEXPR(e) __builtin_constant_p(e) ? (e) : (e)
107 #   endif
108 
109 #   define MATH_CONSTEXPR_INIT
110 #   define MATH_DEFAULT_CTOR = default;
111 #   define MATH_DEFAULT_CTOR_CONSTEXPR
112 #   define CONSTEXPR_IF_NOT_MSVC constexpr
113 
114 #endif // _MSC_VER
115 
116 namespace filament::math {
117 
118 // MSVC 2019 16.4 doesn't seem to like it when we specialize std::is_arithmetic for
119 // filament::math::half, so we're forced to create our own is_arithmetic here and specialize it
120 // inside of half.h.
121 template<typename T>
122 struct is_arithmetic : std::integral_constant<bool,
123         std::is_integral<T>::value || std::is_floating_point<T>::value> {
124 };
125 
126 } // filament::math
127 
128 #endif // PATH_MATH_COMPILER_H
129