Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-06-08 18:37:43 +0300
committerJacques Lucke <jacques@blender.org>2020-06-08 18:37:43 +0300
commit0a907657d4d525d320e0c8518f583b7210736214 (patch)
tree10ca57cfaa0af568686ed309af163e32442a87e5 /source/blender
parentb5846ebce7863a59f6bbd00cf676486a7b4e0b76 (diff)
Functions: Run-time type system and index mask
This adds a new `CPPType` that encapsulates information about how to handle instances of a specific data type. This is necessary for the function evaluation system, which will be used to evaluate most of the particle node trees. Furthermore, this adds an `IndexMask` class which offers a surprisingly useful abstraction over an array containing unsigned integers. It makes two assumptions about the underlying integer array: * The integers are in ascending order. * There are no duplicates. `IndexMask` will be used to "select" certain particles that will be processed in a data-oriented way. Sometimes, operations don't have to be applied to all particles, but only some, those that are in the indexed by the `IndexMask`. The two limitations imposed by an `IndexMask` allow for better performance. Reviewers: brecht Differential Revision: https://developer.blender.org/D7957
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh212
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/functions/CMakeLists.txt40
-rw-r--r--source/blender/functions/FN_cpp_type.hh726
-rw-r--r--source/blender/functions/FN_cpp_types.hh48
-rw-r--r--source/blender/functions/intern/cpp_types.cc41
7 files changed, 1069 insertions, 0 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 203b6da272f..fc1cd28312e 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -114,6 +114,7 @@ add_subdirectory(modifiers)
add_subdirectory(gpencil_modifiers)
add_subdirectory(shader_fx)
add_subdirectory(io)
+add_subdirectory(functions)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
new file mode 100644
index 00000000000..96ab8906bd4
--- /dev/null
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -0,0 +1,212 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_INDEX_MASK_HH__
+#define __BLI_INDEX_MASK_HH__
+
+/** \file
+ * \ingroup bli
+ *
+ * An IndexMask references an array of unsigned integers with the following property:
+ * The integers must be in ascending order and there must not be duplicates.
+ *
+ * Remember that the array is only referenced and not owned by an IndexMask instance.
+ *
+ * In most cases the integers in the array represent some indices into another array. So they
+ * "select" or "mask" a some elements in that array. Hence the name IndexMask.
+ *
+ * The invariant stated above has the nice property that it makes it easy to check if an integer
+ * array is an IndexRange, i.e. no indices are skipped. That allows functions to implement two code
+ * paths: One where it iterates over the index array and one where it iterates over the index
+ * range. The latter one is more efficient due to less memory reads and potential usage of SIMD
+ * instructions.
+ *
+ * The IndexMask.foreach_index method helps writing code that implements both code paths at the
+ * same time.
+ */
+
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+
+namespace BLI {
+
+class IndexMask {
+ private:
+ /* The underlying reference to sorted integers. */
+ ArrayRef<uint> m_indices;
+
+ public:
+ /* Creates an IndexMask that contains no indices. */
+ IndexMask() = default;
+
+ /**
+ * Create an IndexMask using the given integer array.
+ * This constructor asserts that the given integers are in ascending order and that there are no
+ * duplicates.
+ */
+ IndexMask(ArrayRef<uint> indices) : m_indices(indices)
+ {
+#ifdef DEBUG
+ for (uint i = 1; i < indices.size(); i++) {
+ BLI_assert(indices[i - 1] < indices[i]);
+ }
+#endif
+ }
+
+ /**
+ * Use this method when you know that no indices are skipped. It is more efficient than preparing
+ * an integer array all the time.
+ */
+ IndexMask(IndexRange range) : m_indices(range.as_array_ref())
+ {
+ }
+
+ /**
+ * Construct an IndexMask from a sorted list of indices. Note, the created IndexMask is only
+ * valid as long as the initializer_list is valid.
+ *
+ * Don't do this:
+ * IndexMask mask = {3, 4, 5};
+ *
+ * Do this:
+ * do_something_with_an_index_mask({3, 4, 5});
+ */
+ IndexMask(const std::initializer_list<uint> &indices) : IndexMask(ArrayRef<uint>(indices))
+ {
+ }
+
+ /**
+ * Creates an IndexMask that references the indices [0, n-1].
+ */
+ explicit IndexMask(uint n) : IndexMask(IndexRange(n))
+ {
+ }
+
+ operator ArrayRef<uint>() const
+ {
+ return m_indices;
+ }
+
+ const uint *begin() const
+ {
+ return m_indices.begin();
+ }
+
+ const uint *end() const
+ {
+ return m_indices.end();
+ }
+
+ /**
+ * Returns the n-th index referenced by this IndexMask. The `index_mask` method returns an
+ * IndexRange containing all indices that can be used as parameter here.
+ */
+ uint operator[](uint n) const
+ {
+ return m_indices[n];
+ }
+
+ /**
+ * Returns the minimum size an array has to have, if the integers in this IndexMask are going to
+ * be used as indices in that array.
+ */
+ uint min_array_size() const
+ {
+ if (m_indices.size() == 0) {
+ return 0;
+ }
+ else {
+ return m_indices.last() + 1;
+ }
+ }
+
+ ArrayRef<uint> indices() const
+ {
+ return m_indices;
+ }
+
+ /**
+ * Returns true if this IndexMask does not skip any indices. This check requires O(1) time.
+ */
+ bool is_range() const
+ {
+ return m_indices.size() > 0 && m_indices.last() - m_indices.first() == m_indices.size() - 1;
+ }
+
+ /**
+ * Returns the IndexRange referenced by this IndexMask. This method should only be called after
+ * the caller made sure that this IndexMask is actually a range.
+ */
+ IndexRange as_range() const
+ {
+ BLI_assert(this->is_range());
+ return IndexRange{m_indices.first(), m_indices.size()};
+ }
+
+ /**
+ * Calls the given callback for every referenced index. The callback has to take one unsigned
+ * integer as parameter.
+ *
+ * This method implements different code paths for the cases when the IndexMask represents a
+ * range or not.
+ */
+ template<typename CallbackT> void foreach_index(const CallbackT &callback) const
+ {
+ if (this->is_range()) {
+ IndexRange range = this->as_range();
+ for (uint i : range) {
+ callback(i);
+ }
+ }
+ else {
+ for (uint i : m_indices) {
+ callback(i);
+ }
+ }
+ }
+
+ /**
+ * Returns an IndexRange that can be used to index this IndexMask.
+ *
+ * The range is [0, number of indices - 1].
+ *
+ * This is not to be confused with the `as_range` method.
+ */
+ IndexRange index_range() const
+ {
+ return m_indices.index_range();
+ }
+
+ /**
+ * Returns the largest index that is referenced by this IndexMask.
+ */
+ uint last() const
+ {
+ return m_indices.last();
+ }
+
+ /**
+ * Returns the number of indices referenced by this IndexMask.
+ */
+ uint size() const
+ {
+ return m_indices.size();
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_INDEX_MASK_HH__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 7757b838afe..73b35a17ec2 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -189,6 +189,7 @@ set(SRC
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
+ BLI_index_mask.hh
BLI_index_range.hh
BLI_iterator.h
BLI_jitter_2d.h
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
new file mode 100644
index 00000000000..9ce1d3ac2fe
--- /dev/null
+++ b/source/blender/functions/CMakeLists.txt
@@ -0,0 +1,40 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../blenlib
+ ../makesdna
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ intern/cpp_types.cc
+
+ FN_cpp_type.hh
+ FN_cpp_types.hh
+)
+
+set(LIB
+ bf_blenlib
+)
+
+blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
new file mode 100644
index 00000000000..10e95c0341e
--- /dev/null
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -0,0 +1,726 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FN_CPP_TYPE_HH__
+#define __FN_CPP_TYPE_HH__
+
+/** \file
+ * \ingroup functions
+ *
+ * The CPPType class is the core of the runtime-type-system used by the functions system. An
+ * instance of this class can represent any C++ type, that is default-constructable, destructable,
+ * movable and copyable. Therefore it also works for all C types. This restrictions might need to
+ * be removed in the future, but for now every required type has these properties.
+ *
+ * Every type has a size and an alignment. Every function dealing with C++ types in a generic way,
+ * has to make sure that alignment rules are followed. The methods provided by a CPPType instance
+ * will check for correct alignment as well.
+ *
+ * Every type has a name that is for debugging purposes only. It should not be used as identifier.
+ *
+ * To check if two instances of CPPType represent the same type, only their pointers have to be
+ * compared. Any C++ type has at most one corresponding CPPType instance.
+ *
+ * A CPPType instance comes with many methods that allow dealing with types in a generic way. Most
+ * methods come in three variants. Using the construct-default methods as example:
+ * - construct_default(void *ptr):
+ * Constructs a single instance of that type at the given pointer.
+ * - construct_default_n(void *ptr, uint n):
+ * Constructs n instances of that type in an array that starts at the given pointer.
+ * - construct_default_indices(void *ptr, IndexMask index_mask):
+ * Constructs multiple instances of that type in an array that starts at the given pointer.
+ * Only the indices referenced by `index_mask` will by constructed.
+ *
+ * In some cases default-construction does nothing (e.g. for trivial types like int). The
+ * `default_value` method provides some default value anyway that can be copied instead. What the
+ * default value is, depends on the type. Usually it is something like 0 or an empty string.
+ *
+ *
+ * Implementation Considerations
+ * -----------------------------
+ *
+ * Concepts like inheritance are currently not captured by this system. This is not because it is
+ * not possible, but because it was not necessary to add this complexity yet.
+ *
+ * One could also implement CPPType itself using virtual inheritance. However, I found the approach
+ * used now with explicit function pointers to work better. Here are some reasons:
+ * - If CPPType would be inherited once for every used C++ type, we would get a lot of classes
+ * that would only be instanced once each.
+ * - Methods like `construct_default` that operate on a single instance have to be fast. Even this
+ * one necessary indirection using function pointers adds a lot of overhead. If all methods were
+ * virtual, there would be a second level of indirection that increases the overhead even more.
+ * - If it becomes necessary, we could pass the function pointers to C functions more easily than
+ * pointers to virtual member functions.
+ */
+
+#include "BLI_index_mask.hh"
+#include "BLI_math_base.h"
+#include "BLI_string_ref.hh"
+
+namespace FN {
+
+using BLI::IndexMask;
+using BLI::StringRef;
+using BLI::StringRefNull;
+
+class CPPType {
+ public:
+ using ConstructDefaultF = void (*)(void *ptr);
+ using ConstructDefaultNF = void (*)(void *ptr, uint n);
+ using ConstructDefaultIndicesF = void (*)(void *ptr, IndexMask index_mask);
+
+ using DestructF = void (*)(void *ptr);
+ using DestructNF = void (*)(void *ptr, uint n);
+ using DestructIndicesF = void (*)(void *ptr, IndexMask index_mask);
+
+ using CopyToInitializedF = void (*)(const void *src, void *dst);
+ using CopyToInitializedNF = void (*)(const void *src, void *dst, uint n);
+ using CopyToInitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
+
+ using CopyToUninitializedF = void (*)(const void *src, void *dst);
+ using CopyToUninitializedNF = void (*)(const void *src, void *dst, uint n);
+ using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
+
+ using RelocateToInitializedF = void (*)(void *src, void *dst);
+ using RelocateToInitializedNF = void (*)(void *src, void *dst, uint n);
+ using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
+
+ using RelocateToUninitializedF = void (*)(void *src, void *dst);
+ using RelocateToUninitializedNF = void (*)(void *src, void *dst, uint n);
+ using RelocateToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
+
+ using FillInitializedF = void (*)(const void *value, void *dst, uint n);
+ using FillInitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
+
+ using FillUninitializedF = void (*)(const void *value, void *dst, uint n);
+ using FillUninitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
+
+ CPPType(std::string name,
+ uint size,
+ uint 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,
+ const void *default_value)
+ : m_size(size),
+ m_alignment(alignment),
+ m_is_trivially_destructible(is_trivially_destructible),
+ m_construct_default(construct_default),
+ m_construct_default_n(construct_default_n),
+ m_construct_default_indices(construct_default_indices),
+ m_destruct(destruct),
+ m_destruct_n(destruct_n),
+ m_destruct_indices(destruct_indices),
+ m_copy_to_initialized(copy_to_initialized),
+ m_copy_to_initialized_n(copy_to_initialized_n),
+ m_copy_to_initialized_indices(copy_to_initialized_indices),
+ m_copy_to_uninitialized(copy_to_uninitialized),
+ m_copy_to_uninitialized_n(copy_to_uninitialized_n),
+ m_copy_to_uninitialized_indices(copy_to_uninitialized_indices),
+ m_relocate_to_initialized(relocate_to_initialized),
+ m_relocate_to_initialized_n(relocate_to_initialized_n),
+ m_relocate_to_initialized_indices(relocate_to_initialized_indices),
+ m_relocate_to_uninitialized(relocate_to_uninitialized),
+ m_relocate_to_uninitialized_n(relocate_to_uninitialized_n),
+ m_relocate_to_uninitialized_indices(relocate_to_uninitialized_indices),
+ m_fill_initialized(fill_initialized),
+ m_fill_initialized_indices(fill_initialized_indices),
+ m_fill_uninitialized(fill_uninitialized),
+ m_fill_uninitialized_indices(fill_uninitialized_indices),
+ m_default_value(default_value),
+ m_name(name)
+ {
+ BLI_assert(is_power_of_2_i(m_alignment));
+ m_alignment_mask = (uintptr_t)m_alignment - (uintptr_t)1;
+ }
+
+ /**
+ * Returns the name of the type for debugging purposes. This name should not be used as
+ * identifier.
+ */
+ StringRefNull name() const
+ {
+ return m_name;
+ }
+
+ /**
+ * Required memory in bytes for an instance of this type.
+ *
+ * C++ equivalent:
+ * sizeof(T);
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Required memory alignment for an instance of this type.
+ *
+ * C++ equivalent:
+ * alignof(T);
+ */
+ uint alignment() const
+ {
+ return m_alignment;
+ }
+
+ /**
+ * When true, the destructor does not have to be called on this type. This can sometimes be used
+ * for optimization purposes.
+ *
+ * C++ equivalent:
+ * std::is_trivially_destructible<T>::value;
+ */
+ bool is_trivially_destructible() const
+ {
+ return m_is_trivially_destructible;
+ }
+
+ /**
+ * Returns true, when the given pointer fullfills the alignment requirement of this type.
+ */
+ bool pointer_has_valid_alignment(const void *ptr) const
+ {
+ return ((uintptr_t)ptr & m_alignment_mask) == 0;
+ }
+
+ bool pointer_can_point_to_instance(const void *ptr) const
+ {
+ return ptr != nullptr && pointer_has_valid_alignment(ptr);
+ }
+
+ /**
+ * Call the default constructor at the given memory location.
+ * The memory should be uninitialized before this method is called.
+ * For some trivial types (like int), this method does nothing.
+ *
+ * C++ equivalent:
+ * new (ptr) T;
+ */
+ void construct_default(void *ptr) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_construct_default(ptr);
+ }
+
+ void construct_default_n(void *ptr, uint n) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_construct_default_n(ptr, n);
+ }
+
+ void construct_default_indices(void *ptr, IndexMask index_mask) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_construct_default_indices(ptr, index_mask);
+ }
+
+ /**
+ * Call the destructor on the given instance of this type. The pointer must not be nullptr.
+ *
+ * For some trivial types, this does nothing.
+ *
+ * C++ equivalent:
+ * ptr->~T();
+ */
+ void destruct(void *ptr) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_destruct(ptr);
+ }
+
+ void destruct_n(void *ptr, uint n) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_destruct_n(ptr, n);
+ }
+
+ void destruct_indices(void *ptr, IndexMask index_mask) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(ptr));
+
+ m_destruct_indices(ptr, index_mask);
+ }
+
+ /**
+ * Copy an instance of this type from src to dst.
+ *
+ * C++ equivalent:
+ * dst = src;
+ */
+ void copy_to_initialized(const void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_initialized(src, dst);
+ }
+
+ void copy_to_initialized_n(const void *src, void *dst, uint n) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_initialized_n(src, dst, n);
+ }
+
+ void copy_to_initialized_indices(const void *src, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_initialized_indices(src, dst, index_mask);
+ }
+
+ /**
+ * Copy an instance of this type from src to dst.
+ *
+ * The memory pointed to by dst should be uninitialized.
+ *
+ * C++ equivalent:
+ * new (dst) T(src);
+ */
+ void copy_to_uninitialized(const void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_uninitialized(src, dst);
+ }
+
+ void copy_to_uninitialized_n(const void *src, void *dst, uint n) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_uninitialized_n(src, dst, n);
+ }
+
+ void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_copy_to_uninitialized_indices(src, dst, index_mask);
+ }
+
+ /**
+ * Relocates an instance of this type from src to dst. src will point to uninitialized memory
+ * afterwards.
+ *
+ * C++ equivalent:
+ * dst = std::move(src);
+ * src->~T();
+ */
+ void relocate_to_initialized(void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_initialized(src, dst);
+ }
+
+ void relocate_to_initialized_n(void *src, void *dst, uint n) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_initialized_n(src, dst, n);
+ }
+
+ void relocate_to_initialized_indices(void *src, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_initialized_indices(src, dst, index_mask);
+ }
+
+ /**
+ * Relocates an instance of this type from src to dst. src will point to uninitialized memory
+ * afterwards.
+ *
+ * C++ equivalent:
+ * new (dst) T(std::move(src))
+ * src->~T();
+ */
+ void relocate_to_uninitialized(void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_uninitialized(src, dst);
+ }
+
+ void relocate_to_uninitialized_n(void *src, void *dst, uint n) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_uninitialized_n(src, dst, n);
+ }
+
+ void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_relocate_to_uninitialized_indices(src, dst, index_mask);
+ }
+
+ /**
+ * Copy the given value to the first n elements in an array starting at dst.
+ *
+ * Other instances of the same type should live in the array before this method is called.
+ */
+ void fill_initialized(const void *value, void *dst, uint n) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_fill_initialized(value, dst, n);
+ }
+
+ void fill_initialized_indices(const void *value, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_fill_initialized_indices(value, dst, index_mask);
+ }
+
+ /**
+ * Copy the given value to the first n elements in an array starting at dst.
+ *
+ * The array should be uninitialized before this method is called.
+ */
+ void fill_uninitialized(const void *value, void *dst, uint n) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_fill_uninitialized(value, dst, n);
+ }
+
+ void fill_uninitialized_indices(const void *value, void *dst, IndexMask index_mask) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ m_fill_uninitialized_indices(value, dst, index_mask);
+ }
+
+ /**
+ * Get a pointer to a constant value of this type. The specific value depends on the type.
+ * It is usually a zero-initialized or default constructed value.
+ */
+ const void *default_value() const
+ {
+ return m_default_value;
+ }
+
+ /**
+ * Two types only compare equal when their pointer is equal. No two instances of CPPType for the
+ * same C++ type should be created.
+ */
+ friend bool operator==(const CPPType &a, const CPPType &b)
+ {
+ return &a == &b;
+ }
+
+ friend bool operator!=(const CPPType &a, const CPPType &b)
+ {
+ return !(&a == &b);
+ }
+
+ template<typename T> static const CPPType &get();
+
+ private:
+ uint m_size;
+ uint m_alignment;
+ uintptr_t m_alignment_mask;
+ bool m_is_trivially_destructible;
+
+ ConstructDefaultF m_construct_default;
+ ConstructDefaultNF m_construct_default_n;
+ ConstructDefaultIndicesF m_construct_default_indices;
+
+ DestructF m_destruct;
+ DestructNF m_destruct_n;
+ DestructIndicesF m_destruct_indices;
+
+ CopyToInitializedF m_copy_to_initialized;
+ CopyToInitializedNF m_copy_to_initialized_n;
+ CopyToInitializedIndicesF m_copy_to_initialized_indices;
+
+ CopyToUninitializedF m_copy_to_uninitialized;
+ CopyToUninitializedNF m_copy_to_uninitialized_n;
+ CopyToUninitializedIndicesF m_copy_to_uninitialized_indices;
+
+ RelocateToInitializedF m_relocate_to_initialized;
+ RelocateToInitializedNF m_relocate_to_initialized_n;
+ RelocateToInitializedIndicesF m_relocate_to_initialized_indices;
+
+ RelocateToUninitializedF m_relocate_to_uninitialized;
+ RelocateToUninitializedNF m_relocate_to_uninitialized_n;
+ RelocateToUninitializedIndicesF m_relocate_to_uninitialized_indices;
+
+ FillInitializedF m_fill_initialized;
+ FillInitializedIndicesF m_fill_initialized_indices;
+
+ FillUninitializedF m_fill_uninitialized;
+ FillUninitializedIndicesF m_fill_uninitialized_indices;
+
+ const void *m_default_value;
+ std::string m_name;
+};
+
+/* --------------------------------------------------------------------
+ * Utility for creating CPPType instances for C++ types.
+ */
+
+namespace CPPTypeUtil {
+
+template<typename T> void construct_default_cb(void *ptr)
+{
+ BLI::construct_default((T *)ptr);
+}
+template<typename T> void construct_default_n_cb(void *ptr, uint n)
+{
+ for (uint i = 0; i < n; i++) {
+ BLI::construct_default((T *)ptr + i);
+ }
+}
+template<typename T> void construct_default_indices_cb(void *ptr, IndexMask index_mask)
+{
+ index_mask.foreach_index([&](uint i) { BLI::construct_default((T *)ptr + i); });
+}
+
+template<typename T> void destruct_cb(void *ptr)
+{
+ BLI::destruct((T *)ptr);
+}
+template<typename T> void destruct_n_cb(void *ptr, uint n)
+{
+ BLI::destruct_n((T *)ptr, n);
+}
+template<typename T> void destruct_indices_cb(void *ptr, IndexMask index_mask)
+{
+ index_mask.foreach_index([&](uint i) { BLI::destruct((T *)ptr + i); });
+}
+
+template<typename T> void copy_to_initialized_cb(const void *src, void *dst)
+{
+ *(T *)dst = *(T *)src;
+}
+template<typename T> void copy_to_initialized_n_cb(const void *src, void *dst, uint n)
+{
+ const T *src_ = (const T *)src;
+ T *dst_ = (T *)dst;
+
+ for (uint i = 0; i < n; i++) {
+ dst_[i] = src_[i];
+ }
+}
+template<typename T>
+void copy_to_initialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
+{
+ const T *src_ = (const T *)src;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) { dst_[i] = src_[i]; });
+}
+
+template<typename T> void copy_to_uninitialized_cb(const void *src, void *dst)
+{
+ BLI::uninitialized_copy_n((T *)src, 1, (T *)dst);
+}
+template<typename T> void copy_to_uninitialized_n_cb(const void *src, void *dst, uint n)
+{
+ BLI::uninitialized_copy_n((T *)src, n, (T *)dst);
+}
+template<typename T>
+void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
+{
+ const T *src_ = (const T *)src;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) { new (dst_ + i) T(src_[i]); });
+}
+
+template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
+{
+ BLI::relocate((T *)src, (T *)dst);
+}
+template<typename T> void relocate_to_initialized_n_cb(void *src, void *dst, uint n)
+{
+ BLI::relocate_n((T *)src, n, (T *)dst);
+}
+template<typename T>
+void relocate_to_initialized_indices_cb(void *src, void *dst, IndexMask index_mask)
+{
+ T *src_ = (T *)src;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) {
+ dst_[i] = std::move(src_[i]);
+ src_[i].~T();
+ });
+}
+
+template<typename T> void relocate_to_uninitialized_cb(void *src, void *dst)
+{
+ BLI::uninitialized_relocate((T *)src, (T *)dst);
+}
+template<typename T> void relocate_to_uninitialized_n_cb(void *src, void *dst, uint n)
+{
+ BLI::uninitialized_relocate_n((T *)src, n, (T *)dst);
+}
+template<typename T>
+void relocate_to_uninitialized_indices_cb(void *src, void *dst, IndexMask index_mask)
+{
+ T *src_ = (T *)src;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) {
+ new (dst_ + i) T(std::move(src_[i]));
+ src_[i].~T();
+ });
+}
+
+template<typename T> void fill_initialized_cb(const void *value, void *dst, uint n)
+{
+ const T &value_ = *(const T *)value;
+ T *dst_ = (T *)dst;
+
+ for (uint i = 0; i < n; i++) {
+ dst_[i] = value_;
+ }
+}
+template<typename T>
+void fill_initialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
+{
+ const T &value_ = *(const T *)value;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) { dst_[i] = value_; });
+}
+
+template<typename T> void fill_uninitialized_cb(const void *value, void *dst, uint n)
+{
+ const T &value_ = *(const T *)value;
+ T *dst_ = (T *)dst;
+
+ for (uint i = 0; i < n; i++) {
+ new (dst_ + i) T(value_);
+ }
+}
+template<typename T>
+void fill_uninitialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
+{
+ const T &value_ = *(const T *)value;
+ T *dst_ = (T *)dst;
+
+ index_mask.foreach_index([&](uint i) { new (dst_ + i) T(value_); });
+}
+
+} // namespace CPPTypeUtil
+
+template<typename T>
+static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &default_value)
+{
+ using namespace CPPTypeUtil;
+ const CPPType *type = new CPPType(name,
+ sizeof(T),
+ alignof(T),
+ std::is_trivially_destructible<T>::value,
+ construct_default_cb<T>,
+ construct_default_n_cb<T>,
+ construct_default_indices_cb<T>,
+ destruct_cb<T>,
+ destruct_n_cb<T>,
+ destruct_indices_cb<T>,
+ copy_to_initialized_cb<T>,
+ copy_to_initialized_n_cb<T>,
+ copy_to_initialized_indices_cb<T>,
+ copy_to_uninitialized_cb<T>,
+ copy_to_uninitialized_n_cb<T>,
+ copy_to_uninitialized_indices_cb<T>,
+ relocate_to_initialized_cb<T>,
+ relocate_to_initialized_n_cb<T>,
+ relocate_to_initialized_indices_cb<T>,
+ relocate_to_uninitialized_cb<T>,
+ relocate_to_uninitialized_n_cb<T>,
+ relocate_to_uninitialized_indices_cb<T>,
+ fill_initialized_cb<T>,
+ fill_initialized_indices_cb<T>,
+ fill_uninitialized_cb<T>,
+ fill_uninitialized_indices_cb<T>,
+ (const void *)&default_value);
+ return std::unique_ptr<const CPPType>(type);
+}
+
+} // namespace FN
+
+#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \
+ static TYPE_NAME default_value_##IDENTIFIER; \
+ static std::unique_ptr<const FN::CPPType> CPPTYPE_##IDENTIFIER##_owner = \
+ FN::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \
+ const FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \
+ template<> const FN::CPPType &FN::CPPType::get<TYPE_NAME>() \
+ { \
+ return CPPType_##IDENTIFIER; \
+ }
+
+#endif /* __FN_CPP_TYPE_HH__ */
diff --git a/source/blender/functions/FN_cpp_types.hh b/source/blender/functions/FN_cpp_types.hh
new file mode 100644
index 00000000000..eceb43beb9d
--- /dev/null
+++ b/source/blender/functions/FN_cpp_types.hh
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FN_CPP_TYPES_HH__
+#define __FN_CPP_TYPES_HH__
+
+/** \file
+ * \ingroup functions
+ *
+ * This header provides convenient access to CPPType instances for some core types like integer
+ * types.
+ */
+
+#include "FN_cpp_type.hh"
+
+namespace FN {
+
+extern const CPPType &CPPType_bool;
+
+extern const CPPType &CPPType_float;
+extern const CPPType &CPPType_float3;
+extern const CPPType &CPPType_float4x4;
+
+extern const CPPType &CPPType_int32;
+extern const CPPType &CPPType_uint32;
+extern const CPPType &CPPType_uint8;
+
+extern const CPPType &CPPType_Color4f;
+extern const CPPType &CPPType_Color4b;
+
+extern const CPPType &CPPType_string;
+
+} // namespace FN
+
+#endif /* __FN_CPP_TYPES_HH__ */
diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc
new file mode 100644
index 00000000000..3435c9c6eca
--- /dev/null
+++ b/source/blender/functions/intern/cpp_types.cc
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_cpp_types.hh"
+
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_float4x4.hh"
+
+namespace FN {
+
+MAKE_CPP_TYPE(bool, bool)
+
+MAKE_CPP_TYPE(float, float)
+MAKE_CPP_TYPE(float3, BLI::float3)
+MAKE_CPP_TYPE(float4x4, BLI::float4x4)
+
+MAKE_CPP_TYPE(int32, int32_t)
+MAKE_CPP_TYPE(uint32, uint32_t)
+MAKE_CPP_TYPE(uint8, uint8_t)
+
+MAKE_CPP_TYPE(Color4f, BLI::Color4f)
+MAKE_CPP_TYPE(Color4b, BLI::Color4b)
+
+MAKE_CPP_TYPE(string, std::string)
+
+} // namespace FN