Skip to content
Flecs v4.1
utils.hpp
Go to the documentation of this file.
1/**
2 * @file addons/cpp/utils/utils.hpp
3 * @brief Flecs STL (FTL?)
4 *
5 * Minimalistic utilities that allow for STL-like functionality without having
6 * to depend on the actual STL.
7 */
8
9// Macros so that C++ new calls can allocate using ecs_os_api memory allocation functions.
10// Rationale:
11// - Using macros here instead of a templated function because clients might override
12// ecs_os_malloc to contain extra debug info like source tracking location. Using a
13// template function in that scenario would collapse all source locations into said
14// function vs. the actual call site.
15// - FLECS_PLACEMENT_NEW(): exists to remove any naked new calls and make it easy to identify any
16// regressions by grepping for new/delete.
17
18#define FLECS_PLACEMENT_NEW(_ptr, _type) ::new(flecs::_::placement_new_tag, _ptr) _type
19#define FLECS_NEW(_type) FLECS_PLACEMENT_NEW(ecs_os_malloc(sizeof(_type)), _type)
20#define FLECS_DELETE(_ptr) \
21 do { \
22 if (_ptr) { \
23 flecs::_::destruct_obj(_ptr); \
24 ecs_os_free(_ptr); \
25 } \
26 } while (false)
27
28/* Faster (compile-time) alternatives to std::move / std::forward. From:
29 * https://www.foonathan.net/2020/09/move-forward/
30 */
31
32#define FLECS_MOV(...) \
33 static_cast<flecs::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
34
35#define FLECS_FWD(...) \
36 static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
37
38namespace flecs
39{
40
41namespace _
42{
43
44/** @private Placement new tag to disambiguate from other operator new overrides. */
45struct placement_new_tag_t{};
46/** @private Placement new tag instance. */
47constexpr placement_new_tag_t placement_new_tag{};
48/** @private Destruct an object without freeing memory. */
49template<class Ty> inline void destruct_obj(Ty* _ptr) { _ptr->~Ty(); }
50/** @private Destruct and free an object. */
51template<class Ty> inline void free_obj(void* _ptr) {
52 if (_ptr) {
53 destruct_obj(static_cast<Ty*>(_ptr));
54 ecs_os_free(_ptr);
55 }
56}
57
58} // namespace _
59
60} // namespace flecs
61
62// Allows overriding flecs_static_assert, which is useful when testing.
63#ifndef flecs_static_assert
64#define flecs_static_assert(cond, str) static_assert(cond, str)
65#endif
66
67inline void* operator new(size_t, flecs::_::placement_new_tag_t, void* _ptr) noexcept { return _ptr; }
68inline void operator delete(void*, flecs::_::placement_new_tag_t, void*) noexcept { }
69
70namespace flecs
71{
72
73/** Compile-time conditional type selector (faster alternative to std::conditional). */
74template <bool> struct condition;
75
76/** Specialization of condition for false. */
77template <> struct condition<false> {
78 /** Select the second type. */
79 template <typename T, typename F> using type = F;
80};
81
82/** Specialization of condition for true. */
83template <> struct condition<true> {
84 /** Select the first type. */
85 template <typename T, typename F> using type = T;
86};
87
88using std::conditional_t;
89using std::decay_t;
90using std::enable_if_t;
91using std::remove_pointer_t;
92using std::remove_reference_t;
93using std::underlying_type_t;
94using std::is_base_of;
95using std::is_empty;
96using std::is_const;
97using std::is_pointer;
98using std::is_reference;
99using std::is_volatile;
100using std::is_same;
101using std::is_enum;
102using std::is_trivially_constructible;
103using std::is_trivially_move_assignable;
104using std::is_trivially_copy_assignable;
105using std::is_trivially_copy_constructible;
106using std::is_trivially_move_constructible;
107using std::is_trivially_copyable;
108using std::is_move_assignable;
109using std::is_move_constructible;
110using std::is_copy_constructible;
111using std::is_trivially_destructible;
112using std::is_empty_v;
113using std::is_const_v;
114using std::is_pointer_v;
115using std::is_reference_v;
116using std::is_volatile_v;
117using std::is_same_v;
118using std::is_enum_v;
119using std::is_base_of_v;
120using std::is_trivially_constructible_v;
121using std::is_trivially_destructible_v;
122using std::is_trivially_copyable_v;
123using std::is_trivially_move_constructible_v;
124using std::is_trivially_copy_constructible_v;
125using std::is_trivially_move_assignable_v;
126using std::is_trivially_copy_assignable_v;
127using std::is_default_constructible_v;
128using std::is_move_constructible_v;
129using std::is_copy_constructible_v;
130using std::is_move_assignable_v;
131using std::is_copy_assignable_v;
132using std::is_destructible_v;
133
134/** Determine constness even if T is a pointer type. */
135template <typename T>
136using is_const_p = is_const< remove_pointer_t<T> >;
137
138/** Apply const from source type to destination type. */
139template<class Src, class Dst>
140using transcribe_const_t = conditional_t<is_const<Src>::value, Dst const, Dst>;
141
142/** Apply volatile from source type to destination type. */
143template<class Src, class Dst>
144using transcribe_volatile_t = conditional_t<is_volatile<Src>::value, Dst volatile, Dst>;
145
146/** Apply const and volatile from source type to destination type. */
147template<class Src, class Dst>
149
150/** Apply pointer from source type to destination type. */
151template<class Src, class Dst>
152using transcribe_pointer_t = conditional_t<is_pointer<Src>::value, Dst*, Dst>;
153
154/** Apply const, volatile, and pointer from source type to destination type. */
155template<class Src, class Dst>
157
158
159/** Convenience enable_if alias using int as default type.
160 * This enables writing code that's a bit less cluttered when
161 * the templates are used in a template declaration:
162 *
163 * enable_if_t<true>* = nullptr
164 * vs:
165 * if_t<true> = 0
166 */
167template <bool V>
168using if_t = enable_if_t<V, int>;
169
170/** Convenience enable_if alias for negated conditions. */
171template <bool V>
172using if_not_t = enable_if_t<false == V, int>;
173
174/** Trait that marks a component as DontFragment at compile time.
175 * Enable by adding a `static constexpr bool dont_fragment = true` member to
176 * the type, or by specializing the trait to derive from std::true_type. */
177template <typename T, typename = void>
178struct dont_fragment : std::false_type { };
179
180template <typename T>
181struct dont_fragment<T, enable_if_t<T::dont_fragment>> : std::true_type { };
182
183/** Trait that marks a component as Sparse at compile time.
184 * Enable by adding a `static constexpr bool sparse = true` member to the
185 * type, or by specializing the trait to derive from std::true_type. */
186template <typename T, typename = void>
187struct sparse : std::false_type { };
188
189template <typename T>
190struct sparse<T, enable_if_t<T::sparse>> : std::true_type { };
191
192/** OnInstantiate policies that can be assigned to a component at compile
193 * time with the flecs::on_instantiate_trait trait. */
194enum class on_instantiate {
195 override,
196 inherit,
197 dont_inherit
198};
199
200/** Trait that assigns an OnInstantiate policy to a component at compile time.
201 * Enable by adding a `static constexpr auto on_instantiate` member set to a
202 * flecs::on_instantiate value, or by specializing the trait. */
203template <typename T, typename = void>
205 static constexpr bool declared = false;
206 static constexpr flecs::on_instantiate value =
207 flecs::on_instantiate::override;
208};
209
210template <typename T>
211struct on_instantiate_trait<T, enable_if_t<is_same<flecs::on_instantiate,
212 typename std::remove_cv<decltype(T::on_instantiate)>::type>::value>>
213{
214 static constexpr bool declared = true;
215 static constexpr flecs::on_instantiate value = T::on_instantiate;
216};
217
218namespace _
219{
220
221/** @private Utility to prevent a static assert from immediately triggering. */
222template <class... T>
223struct always_false {
224 static const bool value = false;
225};
226
227} // namespace _
228
229} // namespace flecs
230
231#include "array.hpp"
232#include "string.hpp"
233#include "enum.hpp"
234#include "stringstream.hpp"
235#include "function_traits.hpp"
236
237namespace flecs {
238namespace _ {
239
240/** @private Extract the type name from a type using compiler intrinsics. */
241#if defined(__GNUC__) || defined(_WIN32)
242template <typename T>
243inline const char* type_name() {
244 static const size_t len = ECS_FUNC_TYPE_LEN(const char*, type_name, ECS_FUNC_NAME);
245 static char result[len + 1] = {};
246 static const size_t front_len = ECS_FUNC_NAME_FRONT(const char*, type_name);
247 static const char* cppTypeName = ecs_cpp_get_type_name(result, ECS_FUNC_NAME, len, front_len);
248 return cppTypeName;
249}
250#else
251#error "implicit component registration not supported"
252#endif
253
254}
255}
Array class.
Compile-time enum reflection utilities.
FLECS_API char * ecs_cpp_get_type_name(char *type_name, const char *func_name, size_t len, size_t front_len)
Get type name from compiler-generated function name.
Compile-time utilities to inspect properties of functions.
Int to enum.
Definition component.hpp:18
String utility that doesn't implicitly allocate memory.
Wrapper around ecs_strbuf_t that provides a simple stringstream-like API.
F type
Select the second type.
Definition utils.hpp:79
T type
Select the first type.
Definition utils.hpp:85
Compile-time conditional type selector (faster alternative to std::conditional).
Definition utils.hpp:74
Trait that marks a component as DontFragment at compile time.
Definition utils.hpp:178
Trait that assigns an OnInstantiate policy to a component at compile time.
Definition utils.hpp:204
Trait that marks a component as Sparse at compile time.
Definition utils.hpp:187
Type class.
Definition type.hpp:21
enable_if_t< false==V, int > if_not_t
Convenience enable_if alias for negated conditions.
Definition utils.hpp:172
enable_if_t< V, int > if_t
Convenience enable_if alias using int as default type.
Definition utils.hpp:168
on_instantiate
OnInstantiate policies that can be assigned to a component at compile time with the flecs::on_instant...
Definition utils.hpp:194
conditional_t< is_volatile< Src >::value, Dst volatile, Dst > transcribe_volatile_t
Apply volatile from source type to destination type.
Definition utils.hpp:144
transcribe_cv_t< Src, transcribe_pointer_t< Src, Dst > > transcribe_cvp_t
Apply const, volatile, and pointer from source type to destination type.
Definition utils.hpp:156
is_const< remove_pointer_t< T > > is_const_p
Determine constness even if T is a pointer type.
Definition utils.hpp:136
conditional_t< is_const< Src >::value, Dst const, Dst > transcribe_const_t
Apply const from source type to destination type.
Definition utils.hpp:140
conditional_t< is_pointer< Src >::value, Dst *, Dst > transcribe_pointer_t
Apply pointer from source type to destination type.
Definition utils.hpp:152
transcribe_const_t< Src, transcribe_volatile_t< Src, Dst > > transcribe_cv_t
Apply const and volatile from source type to destination type.
Definition utils.hpp:148