From 0a907657d4d525d320e0c8518f583b7210736214 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 8 Jun 2020 17:37:43 +0200 Subject: 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 --- source/blender/CMakeLists.txt | 1 + source/blender/blenlib/BLI_index_mask.hh | 212 ++++++++ source/blender/blenlib/CMakeLists.txt | 1 + source/blender/functions/CMakeLists.txt | 40 ++ source/blender/functions/FN_cpp_type.hh | 726 +++++++++++++++++++++++++++ source/blender/functions/FN_cpp_types.hh | 48 ++ source/blender/functions/intern/cpp_types.cc | 41 ++ 7 files changed, 1069 insertions(+) create mode 100644 source/blender/blenlib/BLI_index_mask.hh create mode 100644 source/blender/functions/CMakeLists.txt create mode 100644 source/blender/functions/FN_cpp_type.hh create mode 100644 source/blender/functions/FN_cpp_types.hh create mode 100644 source/blender/functions/intern/cpp_types.cc (limited to 'source/blender') 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 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 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 &indices) : IndexMask(ArrayRef(indices)) + { + } + + /** + * Creates an IndexMask that references the indices [0, n-1]. + */ + explicit IndexMask(uint n) : IndexMask(IndexRange(n)) + { + } + + operator ArrayRef() 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 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 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::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 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 void construct_default_cb(void *ptr) +{ + BLI::construct_default((T *)ptr); +} +template void construct_default_n_cb(void *ptr, uint n) +{ + for (uint i = 0; i < n; i++) { + BLI::construct_default((T *)ptr + i); + } +} +template void construct_default_indices_cb(void *ptr, IndexMask index_mask) +{ + index_mask.foreach_index([&](uint i) { BLI::construct_default((T *)ptr + i); }); +} + +template void destruct_cb(void *ptr) +{ + BLI::destruct((T *)ptr); +} +template void destruct_n_cb(void *ptr, uint n) +{ + BLI::destruct_n((T *)ptr, n); +} +template void destruct_indices_cb(void *ptr, IndexMask index_mask) +{ + index_mask.foreach_index([&](uint i) { BLI::destruct((T *)ptr + i); }); +} + +template void copy_to_initialized_cb(const void *src, void *dst) +{ + *(T *)dst = *(T *)src; +} +template 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 +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 void copy_to_uninitialized_cb(const void *src, void *dst) +{ + BLI::uninitialized_copy_n((T *)src, 1, (T *)dst); +} +template void copy_to_uninitialized_n_cb(const void *src, void *dst, uint n) +{ + BLI::uninitialized_copy_n((T *)src, n, (T *)dst); +} +template +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 void relocate_to_initialized_cb(void *src, void *dst) +{ + BLI::relocate((T *)src, (T *)dst); +} +template void relocate_to_initialized_n_cb(void *src, void *dst, uint n) +{ + BLI::relocate_n((T *)src, n, (T *)dst); +} +template +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 void relocate_to_uninitialized_cb(void *src, void *dst) +{ + BLI::uninitialized_relocate((T *)src, (T *)dst); +} +template void relocate_to_uninitialized_n_cb(void *src, void *dst, uint n) +{ + BLI::uninitialized_relocate_n((T *)src, n, (T *)dst); +} +template +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 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 +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 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 +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 +static std::unique_ptr 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::value, + construct_default_cb, + construct_default_n_cb, + construct_default_indices_cb, + destruct_cb, + destruct_n_cb, + destruct_indices_cb, + copy_to_initialized_cb, + copy_to_initialized_n_cb, + copy_to_initialized_indices_cb, + copy_to_uninitialized_cb, + copy_to_uninitialized_n_cb, + copy_to_uninitialized_indices_cb, + relocate_to_initialized_cb, + relocate_to_initialized_n_cb, + relocate_to_initialized_indices_cb, + relocate_to_uninitialized_cb, + relocate_to_uninitialized_n_cb, + relocate_to_uninitialized_indices_cb, + fill_initialized_cb, + fill_initialized_indices_cb, + fill_uninitialized_cb, + fill_uninitialized_indices_cb, + (const void *)&default_value); + return std::unique_ptr(type); +} + +} // namespace FN + +#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \ + static TYPE_NAME default_value_##IDENTIFIER; \ + static std::unique_ptr CPPTYPE_##IDENTIFIER##_owner = \ + FN::create_cpp_type(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ + const FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ + template<> const FN::CPPType &FN::CPPType::get() \ + { \ + 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 -- cgit v1.2.3