1 #pragma once
2 
3 /// \file Object.h
4 /// \brief Common macros and basic objects.
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7 
8 #include <cstdint>
9 #include <utility>
10 
11 #define NAMESPACE_SPH_BEGIN namespace Sph {
12 #define NAMESPACE_SPH_END }
13 
14 NAMESPACE_SPH_BEGIN
15 
16 /// Macros for conditional compilation based on selected compiler
17 #ifdef __GNUC__
18 #ifdef __clang__
19 #define SPH_CLANG
20 #else
21 #define SPH_GCC
22 #endif
23 #endif
24 #ifdef _WIN32
25 #define SPH_WIN
26 #endif
27 
28 #ifdef SPH_WIN
29 /// Turn on debug mode when compiling in debug configuration
30 #ifdef _DEBUG
31 #define SPH_DEBUG
32 #endif
33 #endif
34 
35 /// Force inline
36 #ifdef SPH_DEBUG
37 #define INLINE inline
38 #define INL
39 #else
40 #ifdef SPH_WIN
41 #define INLINE __forceinline
42 #define INL
43 #else
44 #define INLINE __attribute__((always_inline)) inline
45 #define INL __attribute__((always_inline))
46 #endif
47 #endif
48 
49 /// No inline
50 #ifdef SPH_WIN
51 #define NO_INLINE __declspec(noinline)
52 #else
53 #define NO_INLINE __attribute__((noinline))
54 #endif
55 
56 #ifdef SPH_WIN
57 #define SPH_MAY_ALIAS
58 #else
59 #define SPH_MAY_ALIAS __attribute__((__may_alias__))
60 #endif
61 
62 #define UNUSED(x)
63 
64 /// \brief Silences the "unused variable" warning for given variable.
65 ///
66 /// \note sizeof is used to make sure x is not evaluated.
67 #define MARK_USED(x) (void)sizeof(x)
68 
69 #ifdef SPH_WIN
70 #define SPH_FALLTHROUGH
71 #else
72 #define SPH_FALLTHROUGH [[fallthrough]];
73 #endif
74 
75 #define DEPRECATED [[deprecated]]
76 
77 /// Branch prediction hints
78 #ifdef SPH_WIN
79 #define SPH_LIKELY(x) x
80 #define SPH_UNLIKELY(x) x
81 #else
82 #define SPH_LIKELY(x) __builtin_expect(bool(x), 1)
83 #define SPH_UNLIKELY(x) __builtin_expect(bool(x), 0)
84 #endif
85 
86 /// Printing function names in assertions
87 #ifdef SPH_WIN
88 #define SPH_PRETTY_FUNCTION __FUNCSIG__
89 #else
90 #define SPH_PRETTY_FUNCTION __PRETTY_FUNCTION__
91 #endif
92 
93 /// \brief Object with deleted copy constructor and copy operator
94 struct Noncopyable {
95     Noncopyable() = default;
96 
97     Noncopyable(const Noncopyable&) = delete;
98     Noncopyable(Noncopyable&&) = default;
99     Noncopyable& operator=(const Noncopyable&) = delete;
100     Noncopyable& operator=(Noncopyable&&) = default;
101 };
102 
103 /// \brief Object with deleted copy and move constructor and copy and move operator
104 struct Immovable {
105     Immovable() = default;
106 
107     Immovable(const Immovable&) = delete;
108     Immovable(Immovable&&) = delete;
109     Immovable& operator=(const Immovable&) = delete;
110     Immovable& operator=(Immovable&&) = delete;
111 };
112 
113 
114 /// \brief Object intended to only be constructed on stack
115 ///
116 /// \note This does not strictly enforce the object is constructed on stack, as we can easily wrap it to
117 /// another class and call operator new on the wrapper.
118 /// And yes, being local variable and being constructed on stack are not the same things. Try to think of a
119 /// better name if you can.
120 class Local {
121     void* operator new(std::size_t) = delete;
122     void* operator new[](std::size_t) = delete;
123     void operator delete(void*) = delete;
124     void operator delete[](void*) = delete;
125 };
126 
127 /// \brief Base class for all polymorphic objects
128 struct Polymorphic {
~PolymorphicPolymorphic129     virtual ~Polymorphic() {}
130 };
131 
132 /// \brief Helper class used to allow calling a function only from within T.
133 template <typename T>
134 class Badge {
135 private:
136     friend T;
137 
Badge()138     Badge() {}
139 };
140 
141 namespace Detail {
142 template <std::size_t N1, std::size_t N2>
143 struct StaticForType {
144     template <typename TVisitor>
actionStaticForType145     INLINE static void action(TVisitor&& visitor) {
146         visitor.template visit<N1>();
147         StaticForType<N1 + 1, N2>::action(std::forward<TVisitor>(visitor));
148     }
149 };
150 template <std::size_t N>
151 struct StaticForType<N, N> {
152     template <typename TVisitor>
153     INLINE static void action(TVisitor&& visitor) {
154         visitor.template visit<N>();
155     }
156 };
157 } // namespace Detail
158 
159 /// Static for loop from n1 to n2, including both values. Takes an object as an argument that must implement
160 /// templated method template<int n> visit(); for loop will pass the current index as a template parameter,
161 /// so that it can be used as a constant expression.
162 template <std::size_t N1, std::size_t N2, typename TVisitor>
163 INLINE void staticFor(TVisitor&& visitor) {
164     Detail::StaticForType<N1, N2>::action(std::forward<TVisitor>(visitor));
165 }
166 
167 namespace Detail {
168 /// \todo can be replaced with fold expressions
169 template <typename... TArgs>
170 void expandPack(TArgs&&...) {}
171 } // namespace Detail
172 
173 template <typename TVisitor, typename... TArgs>
174 INLINE void staticForEach(TVisitor&& visitor, TArgs&&... args) {
175     Detail::expandPack(visitor(std::forward<TArgs>(args))...);
176 }
177 
178 
179 namespace Detail {
180 template <std::size_t I, std::size_t N>
181 struct SelectNthType {
182     template <typename TValue, typename... TOthers>
183     INLINE static decltype(auto) action(TValue&& UNUSED(value), TOthers&&... others) {
184         return SelectNthType<I + 1, N>::action(std::forward<TOthers>(others)...);
185     }
186 };
187 template <std::size_t N>
188 struct SelectNthType<N, N> {
189     template <typename TValue, typename... TOthers>
190     INLINE static decltype(auto) action(TValue&& value, TOthers&&... UNUSED(others)) {
191         return std::forward<TValue>(value);
192     }
193 };
194 } // namespace Detail
195 
196 /// Returns N-th argument from an argument list. The type of the returned argument matches the type of the
197 /// input argument.
198 template <std::size_t N, typename TValue, typename... TOthers>
199 INLINE decltype(auto) selectNth(TValue&& value, TOthers&&... others) {
200     return Detail::SelectNthType<0, N>::action(std::forward<TValue>(value), std::forward<TOthers>(others)...);
201 }
202 
203 NAMESPACE_SPH_END
204