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