1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 #pragma once
18
19 /** \file
20 * \ingroup fn
21 *
22 * The CPPType class is the core of the runtime-type-system used by the functions system. It can
23 * represent C++ types that are default-constructible, destructible, movable, copyable,
24 * equality comparable and hashable. In the future we might want to make some of these properties
25 * optional.
26 *
27 * Every type has a size and an alignment. Every function dealing with C++ types in a generic way,
28 * has to make sure that alignment rules are followed. The methods provided by a CPPType instance
29 * will check for correct alignment as well.
30 *
31 * Every type has a name that is for debugging purposes only. It should not be used as identifier.
32 *
33 * To check if two instances of CPPType represent the same type, only their pointers have to be
34 * compared. Any C++ type has at most one corresponding CPPType instance.
35 *
36 * A CPPType instance comes with many methods that allow dealing with types in a generic way. Most
37 * methods come in three variants. Using the construct-default methods as example:
38 * - construct_default(void *ptr):
39 * Constructs a single instance of that type at the given pointer.
40 * - construct_default_n(void *ptr, int64_t n):
41 * Constructs n instances of that type in an array that starts at the given pointer.
42 * - construct_default_indices(void *ptr, IndexMask mask):
43 * Constructs multiple instances of that type in an array that starts at the given pointer.
44 * Only the indices referenced by `mask` will by constructed.
45 *
46 * In some cases default-construction does nothing (e.g. for trivial types like int). The
47 * `default_value` method provides some default value anyway that can be copied instead. What the
48 * default value is, depends on the type. Usually it is something like 0 or an empty string.
49 *
50 *
51 * Implementation Considerations
52 * -----------------------------
53 *
54 * Concepts like inheritance are currently not captured by this system. This is not because it is
55 * not possible, but because it was not necessary to add this complexity yet.
56 *
57 * One could also implement CPPType itself using virtual inheritance. However, I found the approach
58 * used now with explicit function pointers to work better. Here are some reasons:
59 * - If CPPType would be inherited once for every used C++ type, we would get a lot of classes
60 * that would only be instanced once each.
61 * - Methods like `construct_default` that operate on a single instance have to be fast. Even this
62 * one necessary indirection using function pointers adds a lot of overhead. If all methods were
63 * virtual, there would be a second level of indirection that increases the overhead even more.
64 * - If it becomes necessary, we could pass the function pointers to C functions more easily than
65 * pointers to virtual member functions.
66 */
67
68 #include "BLI_hash.hh"
69 #include "BLI_index_mask.hh"
70 #include "BLI_math_base.h"
71 #include "BLI_string_ref.hh"
72 #include "BLI_utility_mixins.hh"
73
74 namespace blender::fn {
75
76 class CPPType : NonCopyable, NonMovable {
77 public:
78 using ConstructDefaultF = void (*)(void *ptr);
79 using ConstructDefaultNF = void (*)(void *ptr, int64_t n);
80 using ConstructDefaultIndicesF = void (*)(void *ptr, IndexMask mask);
81
82 using DestructF = void (*)(void *ptr);
83 using DestructNF = void (*)(void *ptr, int64_t n);
84 using DestructIndicesF = void (*)(void *ptr, IndexMask mask);
85
86 using CopyToInitializedF = void (*)(const void *src, void *dst);
87 using CopyToInitializedNF = void (*)(const void *src, void *dst, int64_t n);
88 using CopyToInitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
89
90 using CopyToUninitializedF = void (*)(const void *src, void *dst);
91 using CopyToUninitializedNF = void (*)(const void *src, void *dst, int64_t n);
92 using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
93
94 using RelocateToInitializedF = void (*)(void *src, void *dst);
95 using RelocateToInitializedNF = void (*)(void *src, void *dst, int64_t n);
96 using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
97
98 using RelocateToUninitializedF = void (*)(void *src, void *dst);
99 using RelocateToUninitializedNF = void (*)(void *src, void *dst, int64_t n);
100 using RelocateToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
101
102 using FillInitializedF = void (*)(const void *value, void *dst, int64_t n);
103 using FillInitializedIndicesF = void (*)(const void *value, void *dst, IndexMask mask);
104
105 using FillUninitializedF = void (*)(const void *value, void *dst, int64_t n);
106 using FillUninitializedIndicesF = void (*)(const void *value, void *dst, IndexMask mask);
107
108 using DebugPrintF = void (*)(const void *value, std::stringstream &ss);
109 using IsEqualF = bool (*)(const void *a, const void *b);
110 using HashF = uint64_t (*)(const void *value);
111
112 private:
113 int64_t size_;
114 int64_t alignment_;
115 uintptr_t alignment_mask_;
116 bool is_trivially_destructible_;
117
118 ConstructDefaultF construct_default_;
119 ConstructDefaultNF construct_default_n_;
120 ConstructDefaultIndicesF construct_default_indices_;
121
122 DestructF destruct_;
123 DestructNF destruct_n_;
124 DestructIndicesF destruct_indices_;
125
126 CopyToInitializedF copy_to_initialized_;
127 CopyToInitializedNF copy_to_initialized_n_;
128 CopyToInitializedIndicesF copy_to_initialized_indices_;
129
130 CopyToUninitializedF copy_to_uninitialized_;
131 CopyToUninitializedNF copy_to_uninitialized_n_;
132 CopyToUninitializedIndicesF copy_to_uninitialized_indices_;
133
134 RelocateToInitializedF relocate_to_initialized_;
135 RelocateToInitializedNF relocate_to_initialized_n_;
136 RelocateToInitializedIndicesF relocate_to_initialized_indices_;
137
138 RelocateToUninitializedF relocate_to_uninitialized_;
139 RelocateToUninitializedNF relocate_to_uninitialized_n_;
140 RelocateToUninitializedIndicesF relocate_to_uninitialized_indices_;
141
142 FillInitializedF fill_initialized_;
143 FillInitializedIndicesF fill_initialized_indices_;
144
145 FillUninitializedF fill_uninitialized_;
146 FillUninitializedIndicesF fill_uninitialized_indices_;
147
148 DebugPrintF debug_print_;
149 IsEqualF is_equal_;
150 HashF hash_;
151
152 const void *default_value_;
153 std::string name_;
154
155 public:
CPPType(std::string name,int64_t size,int64_t alignment,bool is_trivially_destructible,ConstructDefaultF construct_default,ConstructDefaultNF construct_default_n,ConstructDefaultIndicesF construct_default_indices,DestructF destruct,DestructNF destruct_n,DestructIndicesF destruct_indices,CopyToInitializedF copy_to_initialized,CopyToInitializedNF copy_to_initialized_n,CopyToInitializedIndicesF copy_to_initialized_indices,CopyToUninitializedF copy_to_uninitialized,CopyToUninitializedNF copy_to_uninitialized_n,CopyToUninitializedIndicesF copy_to_uninitialized_indices,RelocateToInitializedF relocate_to_initialized,RelocateToInitializedNF relocate_to_initialized_n,RelocateToInitializedIndicesF relocate_to_initialized_indices,RelocateToUninitializedF relocate_to_uninitialized,RelocateToUninitializedNF relocate_to_uninitialized_n,RelocateToUninitializedIndicesF relocate_to_uninitialized_indices,FillInitializedF fill_initialized,FillInitializedIndicesF fill_initialized_indices,FillUninitializedF fill_uninitialized,FillUninitializedIndicesF fill_uninitialized_indices,DebugPrintF debug_print,IsEqualF is_equal,HashF hash,const void * default_value)156 CPPType(std::string name,
157 int64_t size,
158 int64_t alignment,
159 bool is_trivially_destructible,
160 ConstructDefaultF construct_default,
161 ConstructDefaultNF construct_default_n,
162 ConstructDefaultIndicesF construct_default_indices,
163 DestructF destruct,
164 DestructNF destruct_n,
165 DestructIndicesF destruct_indices,
166 CopyToInitializedF copy_to_initialized,
167 CopyToInitializedNF copy_to_initialized_n,
168 CopyToInitializedIndicesF copy_to_initialized_indices,
169 CopyToUninitializedF copy_to_uninitialized,
170 CopyToUninitializedNF copy_to_uninitialized_n,
171 CopyToUninitializedIndicesF copy_to_uninitialized_indices,
172 RelocateToInitializedF relocate_to_initialized,
173 RelocateToInitializedNF relocate_to_initialized_n,
174 RelocateToInitializedIndicesF relocate_to_initialized_indices,
175 RelocateToUninitializedF relocate_to_uninitialized,
176 RelocateToUninitializedNF relocate_to_uninitialized_n,
177 RelocateToUninitializedIndicesF relocate_to_uninitialized_indices,
178 FillInitializedF fill_initialized,
179 FillInitializedIndicesF fill_initialized_indices,
180 FillUninitializedF fill_uninitialized,
181 FillUninitializedIndicesF fill_uninitialized_indices,
182 DebugPrintF debug_print,
183 IsEqualF is_equal,
184 HashF hash,
185 const void *default_value)
186 : size_(size),
187 alignment_(alignment),
188 is_trivially_destructible_(is_trivially_destructible),
189 construct_default_(construct_default),
190 construct_default_n_(construct_default_n),
191 construct_default_indices_(construct_default_indices),
192 destruct_(destruct),
193 destruct_n_(destruct_n),
194 destruct_indices_(destruct_indices),
195 copy_to_initialized_(copy_to_initialized),
196 copy_to_initialized_n_(copy_to_initialized_n),
197 copy_to_initialized_indices_(copy_to_initialized_indices),
198 copy_to_uninitialized_(copy_to_uninitialized),
199 copy_to_uninitialized_n_(copy_to_uninitialized_n),
200 copy_to_uninitialized_indices_(copy_to_uninitialized_indices),
201 relocate_to_initialized_(relocate_to_initialized),
202 relocate_to_initialized_n_(relocate_to_initialized_n),
203 relocate_to_initialized_indices_(relocate_to_initialized_indices),
204 relocate_to_uninitialized_(relocate_to_uninitialized),
205 relocate_to_uninitialized_n_(relocate_to_uninitialized_n),
206 relocate_to_uninitialized_indices_(relocate_to_uninitialized_indices),
207 fill_initialized_(fill_initialized),
208 fill_initialized_indices_(fill_initialized_indices),
209 fill_uninitialized_(fill_uninitialized),
210 fill_uninitialized_indices_(fill_uninitialized_indices),
211 debug_print_(debug_print),
212 is_equal_(is_equal),
213 hash_(hash),
214 default_value_(default_value),
215 name_(name)
216 {
217 BLI_assert(is_power_of_2_i(alignment_));
218 alignment_mask_ = (uintptr_t)alignment_ - (uintptr_t)1;
219 }
220
221 /**
222 * Two types only compare equal when their pointer is equal. No two instances of CPPType for the
223 * same C++ type should be created.
224 */
operator ==(const CPPType & a,const CPPType & b)225 friend bool operator==(const CPPType &a, const CPPType &b)
226 {
227 return &a == &b;
228 }
229
operator !=(const CPPType & a,const CPPType & b)230 friend bool operator!=(const CPPType &a, const CPPType &b)
231 {
232 return !(&a == &b);
233 }
234
235 template<typename T> static const CPPType &get();
236
237 /**
238 * Returns the name of the type for debugging purposes. This name should not be used as
239 * identifier.
240 */
name() const241 StringRefNull name() const
242 {
243 return name_;
244 }
245
246 /**
247 * Required memory in bytes for an instance of this type.
248 *
249 * C++ equivalent:
250 * sizeof(T);
251 */
size() const252 int64_t size() const
253 {
254 return size_;
255 }
256
257 /**
258 * Required memory alignment for an instance of this type.
259 *
260 * C++ equivalent:
261 * alignof(T);
262 */
alignment() const263 int64_t alignment() const
264 {
265 return alignment_;
266 }
267
268 /**
269 * When true, the destructor does not have to be called on this type. This can sometimes be used
270 * for optimization purposes.
271 *
272 * C++ equivalent:
273 * std::is_trivially_destructible_v<T>;
274 */
is_trivially_destructible() const275 bool is_trivially_destructible() const
276 {
277 return is_trivially_destructible_;
278 }
279
280 /**
281 * Returns true, when the given pointer fulfills the alignment requirement of this type.
282 */
pointer_has_valid_alignment(const void * ptr) const283 bool pointer_has_valid_alignment(const void *ptr) const
284 {
285 return ((uintptr_t)ptr & alignment_mask_) == 0;
286 }
287
pointer_can_point_to_instance(const void * ptr) const288 bool pointer_can_point_to_instance(const void *ptr) const
289 {
290 return ptr != nullptr && pointer_has_valid_alignment(ptr);
291 }
292
293 /**
294 * Call the default constructor at the given memory location.
295 * The memory should be uninitialized before this method is called.
296 * For some trivial types (like int), this method does nothing.
297 *
298 * C++ equivalent:
299 * new (ptr) T;
300 */
construct_default(void * ptr) const301 void construct_default(void *ptr) const
302 {
303 BLI_assert(this->pointer_can_point_to_instance(ptr));
304
305 construct_default_(ptr);
306 }
307
construct_default_n(void * ptr,int64_t n) const308 void construct_default_n(void *ptr, int64_t n) const
309 {
310 BLI_assert(n == 0 || this->pointer_can_point_to_instance(ptr));
311
312 construct_default_n_(ptr, n);
313 }
314
construct_default_indices(void * ptr,IndexMask mask) const315 void construct_default_indices(void *ptr, IndexMask mask) const
316 {
317 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
318
319 construct_default_indices_(ptr, mask);
320 }
321
322 /**
323 * Call the destructor on the given instance of this type. The pointer must not be nullptr.
324 *
325 * For some trivial types, this does nothing.
326 *
327 * C++ equivalent:
328 * ptr->~T();
329 */
destruct(void * ptr) const330 void destruct(void *ptr) const
331 {
332 BLI_assert(this->pointer_can_point_to_instance(ptr));
333
334 destruct_(ptr);
335 }
336
destruct_n(void * ptr,int64_t n) const337 void destruct_n(void *ptr, int64_t n) const
338 {
339 BLI_assert(n == 0 || this->pointer_can_point_to_instance(ptr));
340
341 destruct_n_(ptr, n);
342 }
343
destruct_indices(void * ptr,IndexMask mask) const344 void destruct_indices(void *ptr, IndexMask mask) const
345 {
346 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
347
348 destruct_indices_(ptr, mask);
349 }
350
destruct_cb() const351 DestructF destruct_cb() const
352 {
353 return destruct_;
354 }
355
356 /**
357 * Copy an instance of this type from src to dst.
358 *
359 * C++ equivalent:
360 * dst = src;
361 */
copy_to_initialized(const void * src,void * dst) const362 void copy_to_initialized(const void *src, void *dst) const
363 {
364 BLI_assert(src != dst);
365 BLI_assert(this->pointer_can_point_to_instance(src));
366 BLI_assert(this->pointer_can_point_to_instance(dst));
367
368 copy_to_initialized_(src, dst);
369 }
370
copy_to_initialized_n(const void * src,void * dst,int64_t n) const371 void copy_to_initialized_n(const void *src, void *dst, int64_t n) const
372 {
373 BLI_assert(n == 0 || src != dst);
374 BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
375 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
376
377 copy_to_initialized_n_(src, dst, n);
378 }
379
copy_to_initialized_indices(const void * src,void * dst,IndexMask mask) const380 void copy_to_initialized_indices(const void *src, void *dst, IndexMask mask) const
381 {
382 BLI_assert(mask.size() == 0 || src != dst);
383 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
384 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
385
386 copy_to_initialized_indices_(src, dst, mask);
387 }
388
389 /**
390 * Copy an instance of this type from src to dst.
391 *
392 * The memory pointed to by dst should be uninitialized.
393 *
394 * C++ equivalent:
395 * new (dst) T(src);
396 */
copy_to_uninitialized(const void * src,void * dst) const397 void copy_to_uninitialized(const void *src, void *dst) const
398 {
399 BLI_assert(src != dst);
400 BLI_assert(this->pointer_can_point_to_instance(src));
401 BLI_assert(this->pointer_can_point_to_instance(dst));
402
403 copy_to_uninitialized_(src, dst);
404 }
405
copy_to_uninitialized_n(const void * src,void * dst,int64_t n) const406 void copy_to_uninitialized_n(const void *src, void *dst, int64_t n) const
407 {
408 BLI_assert(n == 0 || src != dst);
409 BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
410 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
411
412 copy_to_uninitialized_n_(src, dst, n);
413 }
414
copy_to_uninitialized_indices(const void * src,void * dst,IndexMask mask) const415 void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask mask) const
416 {
417 BLI_assert(mask.size() == 0 || src != dst);
418 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
419 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
420
421 copy_to_uninitialized_indices_(src, dst, mask);
422 }
423
424 /**
425 * Relocates an instance of this type from src to dst. src will point to uninitialized memory
426 * afterwards.
427 *
428 * C++ equivalent:
429 * dst = std::move(src);
430 * src->~T();
431 */
relocate_to_initialized(void * src,void * dst) const432 void relocate_to_initialized(void *src, void *dst) const
433 {
434 BLI_assert(src != dst);
435 BLI_assert(this->pointer_can_point_to_instance(src));
436 BLI_assert(this->pointer_can_point_to_instance(dst));
437
438 relocate_to_initialized_(src, dst);
439 }
440
relocate_to_initialized_n(void * src,void * dst,int64_t n) const441 void relocate_to_initialized_n(void *src, void *dst, int64_t n) const
442 {
443 BLI_assert(n == 0 || src != dst);
444 BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
445 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
446
447 relocate_to_initialized_n_(src, dst, n);
448 }
449
relocate_to_initialized_indices(void * src,void * dst,IndexMask mask) const450 void relocate_to_initialized_indices(void *src, void *dst, IndexMask mask) const
451 {
452 BLI_assert(mask.size() == 0 || src != dst);
453 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
454 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
455
456 relocate_to_initialized_indices_(src, dst, mask);
457 }
458
459 /**
460 * Relocates an instance of this type from src to dst. src will point to uninitialized memory
461 * afterwards.
462 *
463 * C++ equivalent:
464 * new (dst) T(std::move(src))
465 * src->~T();
466 */
relocate_to_uninitialized(void * src,void * dst) const467 void relocate_to_uninitialized(void *src, void *dst) const
468 {
469 BLI_assert(src != dst);
470 BLI_assert(this->pointer_can_point_to_instance(src));
471 BLI_assert(this->pointer_can_point_to_instance(dst));
472
473 relocate_to_uninitialized_(src, dst);
474 }
475
relocate_to_uninitialized_n(void * src,void * dst,int64_t n) const476 void relocate_to_uninitialized_n(void *src, void *dst, int64_t n) const
477 {
478 BLI_assert(n == 0 || src != dst);
479 BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
480 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
481
482 relocate_to_uninitialized_n_(src, dst, n);
483 }
484
relocate_to_uninitialized_indices(void * src,void * dst,IndexMask mask) const485 void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask mask) const
486 {
487 BLI_assert(mask.size() == 0 || src != dst);
488 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
489 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
490
491 relocate_to_uninitialized_indices_(src, dst, mask);
492 }
493
494 /**
495 * Copy the given value to the first n elements in an array starting at dst.
496 *
497 * Other instances of the same type should live in the array before this method is called.
498 */
fill_initialized(const void * value,void * dst,int64_t n) const499 void fill_initialized(const void *value, void *dst, int64_t n) const
500 {
501 BLI_assert(n == 0 || this->pointer_can_point_to_instance(value));
502 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
503
504 fill_initialized_(value, dst, n);
505 }
506
fill_initialized_indices(const void * value,void * dst,IndexMask mask) const507 void fill_initialized_indices(const void *value, void *dst, IndexMask mask) const
508 {
509 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
510 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
511
512 fill_initialized_indices_(value, dst, mask);
513 }
514
515 /**
516 * Copy the given value to the first n elements in an array starting at dst.
517 *
518 * The array should be uninitialized before this method is called.
519 */
fill_uninitialized(const void * value,void * dst,int64_t n) const520 void fill_uninitialized(const void *value, void *dst, int64_t n) const
521 {
522 BLI_assert(n == 0 || this->pointer_can_point_to_instance(value));
523 BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
524
525 fill_uninitialized_(value, dst, n);
526 }
527
fill_uninitialized_indices(const void * value,void * dst,IndexMask mask) const528 void fill_uninitialized_indices(const void *value, void *dst, IndexMask mask) const
529 {
530 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
531 BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
532
533 fill_uninitialized_indices_(value, dst, mask);
534 }
535
debug_print(const void * value,std::stringstream & ss) const536 void debug_print(const void *value, std::stringstream &ss) const
537 {
538 BLI_assert(this->pointer_can_point_to_instance(value));
539 debug_print_(value, ss);
540 }
541
is_equal(const void * a,const void * b) const542 bool is_equal(const void *a, const void *b) const
543 {
544 BLI_assert(this->pointer_can_point_to_instance(a));
545 BLI_assert(this->pointer_can_point_to_instance(b));
546 return is_equal_(a, b);
547 }
548
hash(const void * value) const549 uint64_t hash(const void *value) const
550 {
551 BLI_assert(this->pointer_can_point_to_instance(value));
552 return hash_(value);
553 }
554
555 /**
556 * Get a pointer to a constant value of this type. The specific value depends on the type.
557 * It is usually a zero-initialized or default constructed value.
558 */
default_value() const559 const void *default_value() const
560 {
561 return default_value_;
562 }
563
hash() const564 uint64_t hash() const
565 {
566 return DefaultHash<const CPPType *>{}(this);
567 }
568
is() const569 template<typename T> bool is() const
570 {
571 return this == &CPPType::get<T>();
572 }
573 };
574
575 /* --------------------------------------------------------------------
576 * Utility for creating CPPType instances for C++ types.
577 */
578
579 namespace cpp_type_util {
580
construct_default_cb(void * ptr)581 template<typename T> void construct_default_cb(void *ptr)
582 {
583 new (ptr) T;
584 }
construct_default_n_cb(void * ptr,int64_t n)585 template<typename T> void construct_default_n_cb(void *ptr, int64_t n)
586 {
587 blender::default_construct_n(static_cast<T *>(ptr), n);
588 }
construct_default_indices_cb(void * ptr,IndexMask mask)589 template<typename T> void construct_default_indices_cb(void *ptr, IndexMask mask)
590 {
591 mask.foreach_index([&](int64_t i) { new (static_cast<T *>(ptr) + i) T; });
592 }
593
destruct_cb(void * ptr)594 template<typename T> void destruct_cb(void *ptr)
595 {
596 (static_cast<T *>(ptr))->~T();
597 }
destruct_n_cb(void * ptr,int64_t n)598 template<typename T> void destruct_n_cb(void *ptr, int64_t n)
599 {
600 blender::destruct_n(static_cast<T *>(ptr), n);
601 }
destruct_indices_cb(void * ptr,IndexMask mask)602 template<typename T> void destruct_indices_cb(void *ptr, IndexMask mask)
603 {
604 T *ptr_ = static_cast<T *>(ptr);
605 mask.foreach_index([&](int64_t i) { ptr_[i].~T(); });
606 }
607
copy_to_initialized_cb(const void * src,void * dst)608 template<typename T> void copy_to_initialized_cb(const void *src, void *dst)
609 {
610 *static_cast<T *>(dst) = *static_cast<const T *>(src);
611 }
copy_to_initialized_n_cb(const void * src,void * dst,int64_t n)612 template<typename T> void copy_to_initialized_n_cb(const void *src, void *dst, int64_t n)
613 {
614 const T *src_ = static_cast<const T *>(src);
615 T *dst_ = static_cast<T *>(dst);
616
617 for (int64_t i = 0; i < n; i++) {
618 dst_[i] = src_[i];
619 }
620 }
621 template<typename T>
copy_to_initialized_indices_cb(const void * src,void * dst,IndexMask mask)622 void copy_to_initialized_indices_cb(const void *src, void *dst, IndexMask mask)
623 {
624 const T *src_ = static_cast<const T *>(src);
625 T *dst_ = static_cast<T *>(dst);
626
627 mask.foreach_index([&](int64_t i) { dst_[i] = src_[i]; });
628 }
629
copy_to_uninitialized_cb(const void * src,void * dst)630 template<typename T> void copy_to_uninitialized_cb(const void *src, void *dst)
631 {
632 blender::uninitialized_copy_n(static_cast<const T *>(src), 1, static_cast<T *>(dst));
633 }
copy_to_uninitialized_n_cb(const void * src,void * dst,int64_t n)634 template<typename T> void copy_to_uninitialized_n_cb(const void *src, void *dst, int64_t n)
635 {
636 blender::uninitialized_copy_n(static_cast<const T *>(src), n, static_cast<T *>(dst));
637 }
638 template<typename T>
copy_to_uninitialized_indices_cb(const void * src,void * dst,IndexMask mask)639 void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask mask)
640 {
641 const T *src_ = static_cast<const T *>(src);
642 T *dst_ = static_cast<T *>(dst);
643
644 mask.foreach_index([&](int64_t i) { new (dst_ + i) T(src_[i]); });
645 }
646
relocate_to_initialized_cb(void * src,void * dst)647 template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
648 {
649 T *src_ = static_cast<T *>(src);
650 T *dst_ = static_cast<T *>(dst);
651
652 *dst_ = std::move(*src_);
653 src_->~T();
654 }
relocate_to_initialized_n_cb(void * src,void * dst,int64_t n)655 template<typename T> void relocate_to_initialized_n_cb(void *src, void *dst, int64_t n)
656 {
657 blender::initialized_relocate_n(static_cast<T *>(src), n, static_cast<T *>(dst));
658 }
relocate_to_initialized_indices_cb(void * src,void * dst,IndexMask mask)659 template<typename T> void relocate_to_initialized_indices_cb(void *src, void *dst, IndexMask mask)
660 {
661 T *src_ = static_cast<T *>(src);
662 T *dst_ = static_cast<T *>(dst);
663
664 mask.foreach_index([&](int64_t i) {
665 dst_[i] = std::move(src_[i]);
666 src_[i].~T();
667 });
668 }
669
relocate_to_uninitialized_cb(void * src,void * dst)670 template<typename T> void relocate_to_uninitialized_cb(void *src, void *dst)
671 {
672 T *src_ = static_cast<T *>(src);
673 T *dst_ = static_cast<T *>(dst);
674
675 new (dst_) T(std::move(*src_));
676 src_->~T();
677 }
relocate_to_uninitialized_n_cb(void * src,void * dst,int64_t n)678 template<typename T> void relocate_to_uninitialized_n_cb(void *src, void *dst, int64_t n)
679 {
680 blender::uninitialized_relocate_n(static_cast<T *>(src), n, static_cast<T *>(dst));
681 }
682 template<typename T>
relocate_to_uninitialized_indices_cb(void * src,void * dst,IndexMask mask)683 void relocate_to_uninitialized_indices_cb(void *src, void *dst, IndexMask mask)
684 {
685 T *src_ = static_cast<T *>(src);
686 T *dst_ = static_cast<T *>(dst);
687
688 mask.foreach_index([&](int64_t i) {
689 new (dst_ + i) T(std::move(src_[i]));
690 src_[i].~T();
691 });
692 }
693
fill_initialized_cb(const void * value,void * dst,int64_t n)694 template<typename T> void fill_initialized_cb(const void *value, void *dst, int64_t n)
695 {
696 const T &value_ = *static_cast<const T *>(value);
697 T *dst_ = static_cast<T *>(dst);
698
699 for (int64_t i = 0; i < n; i++) {
700 dst_[i] = value_;
701 }
702 }
fill_initialized_indices_cb(const void * value,void * dst,IndexMask mask)703 template<typename T> void fill_initialized_indices_cb(const void *value, void *dst, IndexMask mask)
704 {
705 const T &value_ = *static_cast<const T *>(value);
706 T *dst_ = static_cast<T *>(dst);
707
708 mask.foreach_index([&](int64_t i) { dst_[i] = value_; });
709 }
710
fill_uninitialized_cb(const void * value,void * dst,int64_t n)711 template<typename T> void fill_uninitialized_cb(const void *value, void *dst, int64_t n)
712 {
713 const T &value_ = *static_cast<const T *>(value);
714 T *dst_ = static_cast<T *>(dst);
715
716 for (int64_t i = 0; i < n; i++) {
717 new (dst_ + i) T(value_);
718 }
719 }
720 template<typename T>
fill_uninitialized_indices_cb(const void * value,void * dst,IndexMask mask)721 void fill_uninitialized_indices_cb(const void *value, void *dst, IndexMask mask)
722 {
723 const T &value_ = *static_cast<const T *>(value);
724 T *dst_ = static_cast<T *>(dst);
725
726 mask.foreach_index([&](int64_t i) { new (dst_ + i) T(value_); });
727 }
728
debug_print_cb(const void * value,std::stringstream & ss)729 template<typename T> void debug_print_cb(const void *value, std::stringstream &ss)
730 {
731 const T &value_ = *static_cast<const T *>(value);
732 ss << value_;
733 }
734
is_equal_cb(const void * a,const void * b)735 template<typename T> bool is_equal_cb(const void *a, const void *b)
736 {
737 const T &a_ = *static_cast<const T *>(a);
738 const T &b_ = *static_cast<const T *>(b);
739 return a_ == b_;
740 }
741
hash_cb(const void * value)742 template<typename T> uint64_t hash_cb(const void *value)
743 {
744 const T &value_ = *static_cast<const T *>(value);
745 return DefaultHash<T>{}(value_);
746 }
747
748 } // namespace cpp_type_util
749
750 template<typename T>
create_cpp_type(StringRef name,const T & default_value)751 inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &default_value)
752 {
753 using namespace cpp_type_util;
754 const CPPType *type = new CPPType(name,
755 sizeof(T),
756 alignof(T),
757 std::is_trivially_destructible_v<T>,
758 construct_default_cb<T>,
759 construct_default_n_cb<T>,
760 construct_default_indices_cb<T>,
761 destruct_cb<T>,
762 destruct_n_cb<T>,
763 destruct_indices_cb<T>,
764 copy_to_initialized_cb<T>,
765 copy_to_initialized_n_cb<T>,
766 copy_to_initialized_indices_cb<T>,
767 copy_to_uninitialized_cb<T>,
768 copy_to_uninitialized_n_cb<T>,
769 copy_to_uninitialized_indices_cb<T>,
770 relocate_to_initialized_cb<T>,
771 relocate_to_initialized_n_cb<T>,
772 relocate_to_initialized_indices_cb<T>,
773 relocate_to_uninitialized_cb<T>,
774 relocate_to_uninitialized_n_cb<T>,
775 relocate_to_uninitialized_indices_cb<T>,
776 fill_initialized_cb<T>,
777 fill_initialized_indices_cb<T>,
778 fill_uninitialized_cb<T>,
779 fill_uninitialized_indices_cb<T>,
780 debug_print_cb<T>,
781 is_equal_cb<T>,
782 hash_cb<T>,
783 static_cast<const void *>(&default_value));
784 return std::unique_ptr<const CPPType>(type);
785 }
786
787 } // namespace blender::fn
788
789 #define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \
790 template<> const blender::fn::CPPType &blender::fn::CPPType::get<TYPE_NAME>() \
791 { \
792 static TYPE_NAME default_value; \
793 static std::unique_ptr<const CPPType> cpp_type = blender::fn::create_cpp_type<TYPE_NAME>( \
794 STRINGIFY(IDENTIFIER), default_value); \
795 return *cpp_type; \
796 }
797