From 2252bc6a5527cd7360d1ccfe7a2d1bc640a8dfa6 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 18 Mar 2022 10:57:45 +0100 Subject: BLI: move CPPType to blenlib For more detail about `CPPType`, see `BLI_cpp_type.hh` and D14367. Differential Revision: https://developer.blender.org/D14367 --- source/blender/blenkernel/BKE_attribute_access.hh | 4 +- source/blender/blenkernel/BKE_attribute_math.hh | 7 +- source/blender/blenkernel/BKE_geometry_set.hh | 6 +- source/blender/blenkernel/BKE_mesh_sample.hh | 1 - source/blender/blenkernel/BKE_node.h | 4 +- source/blender/blenkernel/BKE_type_conversions.hh | 2 - .../blender/blenkernel/intern/attribute_access.cc | 12 +- .../intern/geometry_component_instances.cc | 4 +- source/blender/blenlib/BLI_cpp_type.hh | 654 +++++++++++++++++++++ source/blender/blenlib/BLI_cpp_type_make.hh | 250 ++++++++ source/blender/blenlib/CMakeLists.txt | 4 + source/blender/blenlib/intern/cpp_type.cc | 23 + source/blender/blenlib/tests/BLI_cpp_type_test.cc | 326 ++++++++++ .../editors/geometry/geometry_attributes.cc | 1 - .../editors/sculpt_paint/curves_sculpt_ops.cc | 1 - source/blender/editors/space_node/node_draw.cc | 1 - .../space_spreadsheet/spreadsheet_column.cc | 5 +- .../space_spreadsheet/spreadsheet_column_values.hh | 2 +- source/blender/functions/CMakeLists.txt | 3 - source/blender/functions/FN_cpp_type.hh | 635 -------------------- source/blender/functions/FN_cpp_type_make.hh | 251 -------- source/blender/functions/FN_field.hh | 6 +- source/blender/functions/FN_field_cpp_type.hh | 8 +- source/blender/functions/FN_generic_array.hh | 2 +- source/blender/functions/FN_generic_pointer.hh | 2 +- source/blender/functions/FN_generic_span.hh | 3 +- source/blender/functions/FN_multi_function.hh | 1 - .../functions/FN_multi_function_data_type.hh | 2 +- source/blender/functions/intern/cpp_types.cc | 29 +- source/blender/functions/tests/FN_cpp_type_test.cc | 326 ---------- source/blender/functions/tests/FN_field_test.cc | 2 +- .../blender/geometry/intern/realize_instances.cc | 1 - source/blender/modifiers/intern/MOD_nodes.cc | 1 + .../modifiers/intern/MOD_nodes_evaluator.cc | 1 - source/blender/nodes/NOD_geometry_exec.hh | 1 - .../blender/nodes/NOD_geometry_nodes_eval_log.hh | 4 +- .../blender/nodes/geometry/node_geometry_exec.cc | 8 +- .../nodes/intern/geometry_nodes_eval_log.cc | 1 - source/blender/nodes/intern/node_socket.cc | 48 +- 39 files changed, 1320 insertions(+), 1322 deletions(-) create mode 100644 source/blender/blenlib/BLI_cpp_type.hh create mode 100644 source/blender/blenlib/BLI_cpp_type_make.hh create mode 100644 source/blender/blenlib/intern/cpp_type.cc create mode 100644 source/blender/blenlib/tests/BLI_cpp_type_test.cc delete mode 100644 source/blender/functions/FN_cpp_type.hh delete mode 100644 source/blender/functions/FN_cpp_type_make.hh delete mode 100644 source/blender/functions/tests/FN_cpp_type_test.cc diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 500f386dcc0..e36163878a5 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -4,7 +4,6 @@ #include -#include "FN_cpp_type.hh" #include "FN_generic_span.hh" #include "FN_generic_virtual_array.hh" @@ -166,7 +165,6 @@ using AttributeForeachCallback = blender::FunctionRef blender::VArray get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const { - const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get(); + const blender::CPPType &cpp_type = blender::CPPType::get(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); GVArray varray = this->get_for_read(attribute_id, type, &default_value); return varray.typed(); diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 42bff89922b..9e97979fde9 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -4,17 +4,14 @@ #include "BLI_array.hh" #include "BLI_color.hh" +#include "BLI_cpp_type.hh" #include "BLI_math_vector.h" #include "BLI_math_vector.hh" #include "DNA_customdata_types.h" -#include "FN_cpp_type.hh" - namespace blender::attribute_math { -using fn::CPPType; - /** * Utility function that simplifies calling a templated function based on a custom data type. */ @@ -50,7 +47,7 @@ inline void convert_to_static_type(const CustomDataType data_type, const Func &f } template -inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func) +inline void convert_to_static_type(const CPPType &cpp_type, const Func &func) { if (cpp_type.is()) { func(float()); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 0e121068cbc..372922a24d2 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -212,7 +212,7 @@ class GeometryComponent { const AttributeDomain domain, const T &default_value) const { - const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get(); + const blender::CPPType &cpp_type = blender::CPPType::get(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_get_for_read(attribute_id, domain, type, &default_value) .template typed(); @@ -240,7 +240,7 @@ class GeometryComponent { const AttributeDomain domain, const T default_value) { - const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get(); + const blender::CPPType &cpp_type = blender::CPPType::get(); const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value); } @@ -260,7 +260,7 @@ class GeometryComponent { blender::bke::OutputAttribute_Typed attribute_try_get_for_output_only( const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) { - const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get(); + const blender::CPPType &cpp_type = blender::CPPType::get(); const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_try_get_for_output_only(attribute_id, domain, data_type); } diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh index 9fe5bd3c531..a51dc7eef2f 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.hh +++ b/source/blender/blenkernel/BKE_mesh_sample.hh @@ -21,7 +21,6 @@ class OutputAttribute; namespace blender::bke::mesh_surface_sample { -using fn::CPPType; using fn::GMutableSpan; using fn::GSpan; using fn::GVArray; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 3e964b038c4..fa199300780 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -99,6 +99,7 @@ typedef struct bNodeSocketTemplate { * However, achieving this requires quite a few changes currently. */ #ifdef __cplusplus namespace blender { +class CPPType; namespace nodes { class NodeMultiFunctionBuilder; class GeoNodeExecParams; @@ -106,12 +107,11 @@ class NodeDeclarationBuilder; class GatherLinkSearchOpParams; } // namespace nodes namespace fn { -class CPPType; class MFDataType; } // namespace fn } // namespace blender -using CPPTypeHandle = blender::fn::CPPType; +using CPPTypeHandle = blender::CPPType; using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder); diff --git a/source/blender/blenkernel/BKE_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh index e66982aa04c..8d3b2730a9c 100644 --- a/source/blender/blenkernel/BKE_type_conversions.hh +++ b/source/blender/blenkernel/BKE_type_conversions.hh @@ -6,8 +6,6 @@ namespace blender::bke { -using fn::CPPType; - struct ConversionFunctions { const fn::MultiFunction *multi_function; void (*convert_single_to_initialized)(const void *src, void *dst); diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 2f07ee55d79..f79e8ee7653 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -54,7 +54,7 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i return stream; } -const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) +const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -77,7 +77,7 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty return nullptr; } -CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type) +CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) { if (type.is()) { return CD_PROP_FLOAT; @@ -1102,7 +1102,7 @@ std::optional GeometryComponent::attribute_get_meta_data( } static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray, - const blender::fn::CPPType &to_type) + const blender::CPPType &to_type) { const blender::bke::DataTypeConversions &conversions = blender::bke::get_implicit_type_conversions(); @@ -1127,7 +1127,7 @@ blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( } } - const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); + const blender::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); if (varray.type() != *cpp_type) { varray = try_adapt_data_type(std::move(varray), *cpp_type); @@ -1165,7 +1165,7 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( if (!attribute) { return {}; } - const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); + const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(type != nullptr); if (attribute.varray.type() == *type) { return attribute; @@ -1184,7 +1184,7 @@ blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeID if (varray) { return varray; } - const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); + const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); if (default_value == nullptr) { default_value = type->default_value(); } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 0cb2b0e812b..75384b5c420 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -20,7 +20,7 @@ #include "attribute_access_intern.hh" -#include "FN_cpp_type_make.hh" +#include "BLI_cpp_type_make.hh" using blender::float4x4; using blender::IndexMask; @@ -31,7 +31,7 @@ using blender::Span; using blender::VectorSet; using blender::fn::GSpan; -MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None) +BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None) /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation diff --git a/source/blender/blenlib/BLI_cpp_type.hh b/source/blender/blenlib/BLI_cpp_type.hh new file mode 100644 index 00000000000..ae6a87b4b68 --- /dev/null +++ b/source/blender/blenlib/BLI_cpp_type.hh @@ -0,0 +1,654 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * The `CPPType` class allows working with arbitrary C++ types in a generic way. An instance of + * #CPPType wraps exactly one type like `int` or `std::string`. + * + * With #CPPType one can write generic data structures and algorithms. That is similar to what C++ + * templates allow. The difference is that when using templates, the types have to be known at + * compile time and the code has to be instantiated multiple times. On the other hand, when using + * #CPPType, the data type only has to be known at run-time, and the code only has to be compiled + * once. Whether #CPPType or classic c++ templates should be used depends on the context: + * - If the data type is not known at run-time, #CPPType should be used. + * - If the data type is known to be one of a few, it depends on how performance sensitive the code + * is. + * - If it it's a small hot loop, a template can be used to optimize for every type (at the + * cost of longer compile time, a larger binary and the complexity that comes from using + * templates). + * - If the code is not performance sensitive, it usually makes sense to use #CPPType instead. + * - Sometimes a combination can make sense. Optimized code can be be generated at compile-time for + * some types, while there is a fallback code path using #CPPType for all other types. + * + * Under some circumstances, #CPPType serves a similar role as #std::type_info. However, #CPPType + * has much more utility because it contains methods for actually working with instances of the + * type. + * + * 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 default-construct methods as an example: + * - `default_construct(void *ptr)`: + * Constructs a single instance of that type at the given pointer. + * - `default_construct_n(void *ptr, int64_t n)`: + * Constructs n instances of that type in an array that starts at the given pointer. + * - `default_construct_indices(void *ptr, IndexMask mask)`: + * Constructs multiple instances of that type in an array that starts at the given pointer. + * Only the indices referenced by `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 methods and a child class for every + * wrapped type. However, the approach used now with explicit function pointers to works 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 `default_construct` 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_hash.hh" +#include "BLI_index_mask.hh" +#include "BLI_math_base.h" +#include "BLI_string_ref.hh" +#include "BLI_utility_mixins.hh" + +/** + * Different types support different features. Features like copy constructability can be detected + * automatically easily. For some features this is harder as of C++17. Those have flags in this + * enum and need to be determined by the programmer. + */ +enum class CPPTypeFlags { + None = 0, + Hashable = 1 << 0, + Printable = 1 << 1, + EqualityComparable = 1 << 2, + + BasicType = Hashable | Printable | EqualityComparable, +}; +ENUM_OPERATORS(CPPTypeFlags, CPPTypeFlags::EqualityComparable) + +namespace blender { + +/** Utility class to pass template parameters to constructor of `CPPType`. */ +template struct CPPTypeParam { +}; + +class CPPType : NonCopyable, NonMovable { + private: + int64_t size_ = 0; + int64_t alignment_ = 0; + uintptr_t alignment_mask_ = 0; + bool is_trivial_ = false; + bool is_trivially_destructible_ = false; + bool has_special_member_functions_ = false; + + void (*default_construct_)(void *ptr) = nullptr; + void (*default_construct_indices_)(void *ptr, IndexMask mask) = nullptr; + + void (*destruct_)(void *ptr) = nullptr; + void (*destruct_indices_)(void *ptr, IndexMask mask) = nullptr; + + void (*copy_assign_)(const void *src, void *dst) = nullptr; + void (*copy_assign_indices_)(const void *src, void *dst, IndexMask mask) = nullptr; + + void (*copy_construct_)(const void *src, void *dst) = nullptr; + void (*copy_construct_indices_)(const void *src, void *dst, IndexMask mask) = nullptr; + + void (*move_assign_)(void *src, void *dst) = nullptr; + void (*move_assign_indices_)(void *src, void *dst, IndexMask mask) = nullptr; + + void (*move_construct_)(void *src, void *dst) = nullptr; + void (*move_construct_indices_)(void *src, void *dst, IndexMask mask) = nullptr; + + void (*relocate_assign_)(void *src, void *dst) = nullptr; + void (*relocate_assign_indices_)(void *src, void *dst, IndexMask mask) = nullptr; + + void (*relocate_construct_)(void *src, void *dst) = nullptr; + void (*relocate_construct_indices_)(void *src, void *dst, IndexMask mask) = nullptr; + + void (*fill_assign_indices_)(const void *value, void *dst, IndexMask mask) = nullptr; + + void (*fill_construct_indices_)(const void *value, void *dst, IndexMask mask) = nullptr; + + void (*print_)(const void *value, std::stringstream &ss) = nullptr; + bool (*is_equal_)(const void *a, const void *b) = nullptr; + uint64_t (*hash_)(const void *value) = nullptr; + + const void *default_value_ = nullptr; + std::string debug_name_; + + public: + template CPPType(CPPTypeParam, StringRef debug_name); + virtual ~CPPType() = default; + + /** + * 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); + } + + /** + * Get the `CPPType` that corresponds to a specific static type. + * This only works for types that actually implement the template specialization using + * `BLI_CPP_TYPE_MAKE`. + */ + template static const CPPType &get() + { + return CPPType::get_impl>(); + } + template static const CPPType &get_impl(); + + /** + * Returns the name of the type for debugging purposes. This name should not be used as + * identifier. + */ + StringRefNull name() const + { + return debug_name_; + } + + /** + * Required memory in bytes for an instance of this type. + * + * C++ equivalent: + * `sizeof(T);` + */ + int64_t size() const + { + return size_; + } + + /** + * Required memory alignment for an instance of this type. + * + * C++ equivalent: + * alignof(T); + */ + int64_t alignment() const + { + return 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_v; + */ + bool is_trivially_destructible() const + { + return is_trivially_destructible_; + } + + /** + * When true, the value is like a normal C type, it can be copied around with #memcpy and does + * not have to be destructed. + * + * C++ equivalent: + * std::is_trivial_v; + */ + bool is_trivial() const + { + return is_trivial_; + } + + bool is_default_constructible() const + { + return default_construct_ != nullptr; + } + + bool is_copy_constructible() const + { + return copy_assign_ != nullptr; + } + + bool is_move_constructible() const + { + return move_assign_ != nullptr; + } + + bool is_destructible() const + { + return destruct_ != nullptr; + } + + bool is_copy_assignable() const + { + return copy_assign_ != nullptr; + } + + bool is_move_assignable() const + { + return copy_construct_ != nullptr; + } + + bool is_printable() const + { + return print_ != nullptr; + } + + bool is_equality_comparable() const + { + return is_equal_ != nullptr; + } + + bool is_hashable() const + { + return hash_ != nullptr; + } + + /** + * Returns true, when the type has the following functions: + * - Default constructor. + * - Copy constructor. + * - Move constructor. + * - Copy assignment operator. + * - Move assignment operator. + * - Destructor. + */ + bool has_special_member_functions() const + { + return has_special_member_functions_; + } + + /** + * Returns true, when the given pointer fulfills the alignment requirement of this type. + */ + bool pointer_has_valid_alignment(const void *ptr) const + { + return ((uintptr_t)ptr & 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 default_construct(void *ptr) const + { + BLI_assert(this->pointer_can_point_to_instance(ptr)); + + default_construct_(ptr); + } + + void default_construct_n(void *ptr, int64_t n) const + { + this->default_construct_indices(ptr, IndexMask(n)); + } + + void default_construct_indices(void *ptr, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr)); + + default_construct_indices_(ptr, 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)); + + destruct_(ptr); + } + + void destruct_n(void *ptr, int64_t n) const + { + this->destruct_indices(ptr, IndexMask(n)); + } + + void destruct_indices(void *ptr, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr)); + + destruct_indices_(ptr, mask); + } + + /** + * Copy an instance of this type from src to dst. + * + * C++ equivalent: + * dst = src; + */ + void copy_assign(const void *src, void *dst) const + { + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + copy_assign_(src, dst); + } + + void copy_assign_n(const void *src, void *dst, int64_t n) const + { + this->copy_assign_indices(src, dst, IndexMask(n)); + } + + void copy_assign_indices(const void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + copy_assign_indices_(src, dst, 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_construct(const void *src, void *dst) const + { + BLI_assert(src != dst || is_trivial_); + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + copy_construct_(src, dst); + } + + void copy_construct_n(const void *src, void *dst, int64_t n) const + { + this->copy_construct_indices(src, dst, IndexMask(n)); + } + + void copy_construct_indices(const void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + copy_construct_indices_(src, dst, mask); + } + + /** + * Move an instance of this type from src to dst. + * + * The memory pointed to by dst should be initialized. + * + * C++ equivalent: + * dst = std::move(src); + */ + void move_assign(void *src, void *dst) const + { + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + move_assign_(src, dst); + } + + void move_assign_n(void *src, void *dst, int64_t n) const + { + this->move_assign_indices(src, dst, IndexMask(n)); + } + + void move_assign_indices(void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + move_assign_indices_(src, dst, mask); + } + + /** + * Move an instance of this type from src to dst. + * + * The memory pointed to by dst should be uninitialized. + * + * C++ equivalent: + * new (dst) T(std::move(src)); + */ + void move_construct(void *src, void *dst) const + { + BLI_assert(src != dst || is_trivial_); + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + move_construct_(src, dst); + } + + void move_construct_n(void *src, void *dst, int64_t n) const + { + this->move_construct_indices(src, dst, IndexMask(n)); + } + + void move_construct_indices(void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + move_construct_indices_(src, dst, 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_assign(void *src, void *dst) const + { + BLI_assert(src != dst || is_trivial_); + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + relocate_assign_(src, dst); + } + + void relocate_assign_n(void *src, void *dst, int64_t n) const + { + this->relocate_assign_indices(src, dst, IndexMask(n)); + } + + void relocate_assign_indices(void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + relocate_assign_indices_(src, dst, 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_construct(void *src, void *dst) const + { + BLI_assert(src != dst || is_trivial_); + BLI_assert(this->pointer_can_point_to_instance(src)); + BLI_assert(this->pointer_can_point_to_instance(dst)); + + relocate_construct_(src, dst); + } + + void relocate_construct_n(void *src, void *dst, int64_t n) const + { + this->relocate_construct_indices(src, dst, IndexMask(n)); + } + + void relocate_construct_indices(void *src, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || src != dst); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + relocate_construct_indices_(src, dst, 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_assign_n(const void *value, void *dst, int64_t n) const + { + this->fill_assign_indices(value, dst, IndexMask(n)); + } + + void fill_assign_indices(const void *value, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + fill_assign_indices_(value, dst, 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_construct_n(const void *value, void *dst, int64_t n) const + { + this->fill_construct_indices(value, dst, IndexMask(n)); + } + + void fill_construct_indices(const void *value, void *dst, IndexMask mask) const + { + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value)); + BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); + + fill_construct_indices_(value, dst, mask); + } + + void print(const void *value, std::stringstream &ss) const + { + BLI_assert(this->pointer_can_point_to_instance(value)); + print_(value, ss); + } + + std::string to_string(const void *value) const + { + std::stringstream ss; + this->print(value, ss); + return ss.str(); + } + + void print_or_default(const void *value, std::stringstream &ss, StringRef default_value) const + { + if (this->is_printable()) { + this->print(value, ss); + } + else { + ss << default_value; + } + } + + bool is_equal(const void *a, const void *b) const + { + BLI_assert(this->pointer_can_point_to_instance(a)); + BLI_assert(this->pointer_can_point_to_instance(b)); + return is_equal_(a, b); + } + + bool is_equal_or_false(const void *a, const void *b) const + { + if (this->is_equality_comparable()) { + return this->is_equal(a, b); + } + return false; + } + + uint64_t hash(const void *value) const + { + BLI_assert(this->pointer_can_point_to_instance(value)); + return hash_(value); + } + + uint64_t hash_or_fallback(const void *value, uint64_t fallback_hash) const + { + if (this->is_hashable()) { + return this->hash(value); + } + return fallback_hash; + } + + /** + * 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 default_value_; + } + + uint64_t hash() const + { + return get_default_hash(this); + } + + void (*destruct_fn() const)(void *) + { + return destruct_; + } + + template bool is() const + { + return this == &CPPType::get>(); + } +}; + +} // namespace blender + +/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */ +#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \ + blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name((type).size(), \ + (type).alignment()); \ + void *variable_name = stack_buffer_for_##variable_name.buffer(); diff --git a/source/blender/blenlib/BLI_cpp_type_make.hh b/source/blender/blenlib/BLI_cpp_type_make.hh new file mode 100644 index 00000000000..9100b2b9a0f --- /dev/null +++ b/source/blender/blenlib/BLI_cpp_type_make.hh @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include "BLI_cpp_type.hh" +#include "BLI_utildefines.h" + +namespace blender::cpp_type_util { + +template void default_construct_cb(void *ptr) +{ + new (ptr) T; +} +template void default_construct_indices_cb(void *ptr, IndexMask mask) +{ + mask.foreach_index([&](int64_t i) { new (static_cast(ptr) + i) T; }); +} + +template void destruct_cb(void *ptr) +{ + (static_cast(ptr))->~T(); +} +template void destruct_indices_cb(void *ptr, IndexMask mask) +{ + T *ptr_ = static_cast(ptr); + mask.foreach_index([&](int64_t i) { ptr_[i].~T(); }); +} + +template void copy_assign_cb(const void *src, void *dst) +{ + *static_cast(dst) = *static_cast(src); +} +template void copy_assign_indices_cb(const void *src, void *dst, IndexMask mask) +{ + const T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { dst_[i] = src_[i]; }); +} + +template void copy_construct_cb(const void *src, void *dst) +{ + blender::uninitialized_copy_n(static_cast(src), 1, static_cast(dst)); +} +template void copy_construct_indices_cb(const void *src, void *dst, IndexMask mask) +{ + const T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { new (dst_ + i) T(src_[i]); }); +} + +template void move_assign_cb(void *src, void *dst) +{ + blender::initialized_move_n(static_cast(src), 1, static_cast(dst)); +} +template void move_assign_indices_cb(void *src, void *dst, IndexMask mask) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { dst_[i] = std::move(src_[i]); }); +} + +template void move_construct_cb(void *src, void *dst) +{ + blender::uninitialized_move_n(static_cast(src), 1, static_cast(dst)); +} +template void move_construct_indices_cb(void *src, void *dst, IndexMask mask) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { new (dst_ + i) T(std::move(src_[i])); }); +} + +template void relocate_assign_cb(void *src, void *dst) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + *dst_ = std::move(*src_); + src_->~T(); +} +template void relocate_assign_indices_cb(void *src, void *dst, IndexMask mask) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { + dst_[i] = std::move(src_[i]); + src_[i].~T(); + }); +} + +template void relocate_construct_cb(void *src, void *dst) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + new (dst_) T(std::move(*src_)); + src_->~T(); +} +template void relocate_construct_indices_cb(void *src, void *dst, IndexMask mask) +{ + T *src_ = static_cast(src); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { + new (dst_ + i) T(std::move(src_[i])); + src_[i].~T(); + }); +} + +template void fill_assign_cb(const void *value, void *dst, int64_t n) +{ + const T &value_ = *static_cast(value); + T *dst_ = static_cast(dst); + + for (int64_t i = 0; i < n; i++) { + dst_[i] = value_; + } +} +template void fill_assign_indices_cb(const void *value, void *dst, IndexMask mask) +{ + const T &value_ = *static_cast(value); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { dst_[i] = value_; }); +} + +template void fill_construct_cb(const void *value, void *dst, int64_t n) +{ + const T &value_ = *static_cast(value); + T *dst_ = static_cast(dst); + + for (int64_t i = 0; i < n; i++) { + new (dst_ + i) T(value_); + } +} +template void fill_construct_indices_cb(const void *value, void *dst, IndexMask mask) +{ + const T &value_ = *static_cast(value); + T *dst_ = static_cast(dst); + + mask.foreach_index([&](int64_t i) { new (dst_ + i) T(value_); }); +} + +template void print_cb(const void *value, std::stringstream &ss) +{ + const T &value_ = *static_cast(value); + ss << value_; +} + +template bool is_equal_cb(const void *a, const void *b) +{ + const T &a_ = *static_cast(a); + const T &b_ = *static_cast(b); + return a_ == b_; +} + +template uint64_t hash_cb(const void *value) +{ + const T &value_ = *static_cast(value); + return get_default_hash(value_); +} + +} // namespace blender::cpp_type_util + +namespace blender { + +template +CPPType::CPPType(CPPTypeParam /* unused */, StringRef debug_name) +{ + using namespace cpp_type_util; + + debug_name_ = debug_name; + size_ = (int64_t)sizeof(T); + alignment_ = (int64_t)alignof(T); + is_trivial_ = std::is_trivial_v; + is_trivially_destructible_ = std::is_trivially_destructible_v; + if constexpr (std::is_default_constructible_v) { + default_construct_ = default_construct_cb; + default_construct_indices_ = default_construct_indices_cb; + static T default_value; + default_value_ = (void *)&default_value; + } + if constexpr (std::is_destructible_v) { + destruct_ = destruct_cb; + destruct_indices_ = destruct_indices_cb; + } + if constexpr (std::is_copy_assignable_v) { + copy_assign_ = copy_assign_cb; + copy_assign_indices_ = copy_assign_indices_cb; + } + if constexpr (std::is_copy_constructible_v) { + copy_construct_ = copy_construct_cb; + copy_construct_indices_ = copy_construct_indices_cb; + } + if constexpr (std::is_move_assignable_v) { + move_assign_ = move_assign_cb; + move_assign_indices_ = move_assign_indices_cb; + } + if constexpr (std::is_move_constructible_v) { + move_construct_ = move_construct_cb; + move_construct_indices_ = move_construct_indices_cb; + } + if constexpr (std::is_destructible_v) { + if constexpr (std::is_move_assignable_v) { + relocate_assign_ = relocate_assign_cb; + relocate_assign_indices_ = relocate_assign_indices_cb; + } + if constexpr (std::is_move_constructible_v) { + relocate_construct_ = relocate_construct_cb; + relocate_construct_indices_ = relocate_construct_indices_cb; + } + } + if constexpr (std::is_copy_assignable_v) { + fill_assign_indices_ = fill_assign_indices_cb; + } + if constexpr (std::is_copy_constructible_v) { + fill_construct_indices_ = fill_construct_indices_cb; + } + if constexpr ((bool)(Flags & CPPTypeFlags::Hashable)) { + hash_ = hash_cb; + } + if constexpr ((bool)(Flags & CPPTypeFlags::Printable)) { + print_ = print_cb; + } + if constexpr ((bool)(Flags & CPPTypeFlags::EqualityComparable)) { + is_equal_ = is_equal_cb; + } + + alignment_mask_ = (uintptr_t)alignment_ - (uintptr_t)1; + has_special_member_functions_ = (default_construct_ && copy_construct_ && copy_assign_ && + move_construct_ && move_assign_ && destruct_); +} + +} // namespace blender + +#define BLI_CPP_TYPE_MAKE(IDENTIFIER, TYPE_NAME, FLAGS) \ + template<> const blender::CPPType &blender::CPPType::get_impl() \ + { \ + static CPPType cpp_type{blender::CPPTypeParam(), STRINGIFY(IDENTIFIER)}; \ + return cpp_type; \ + } diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 6e3e84f6495..057d94a6f39 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC intern/boxpack_2d.c intern/buffer.c intern/convexhull_2d.c + intern/cpp_type.cc intern/delaunay_2d.cc intern/dot_export.cc intern/dynlib.c @@ -170,6 +171,8 @@ set(SRC BLI_compiler_typecheck.h BLI_console.h BLI_convexhull_2d.h + BLI_cpp_type_make.hh + BLI_cpp_type.hh BLI_delaunay_2d.h BLI_dial_2d.h BLI_disjoint_set.hh @@ -403,6 +406,7 @@ if(WITH_GTESTS) tests/BLI_array_utils_test.cc tests/BLI_bounds_test.cc tests/BLI_color_test.cc + tests/BLI_cpp_type_test.cc tests/BLI_delaunay_2d_test.cc tests/BLI_disjoint_set_test.cc tests/BLI_edgehash_test.cc diff --git a/source/blender/blenlib/intern/cpp_type.cc b/source/blender/blenlib/intern/cpp_type.cc new file mode 100644 index 00000000000..72ccc54e552 --- /dev/null +++ b/source/blender/blenlib/intern/cpp_type.cc @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" +#include "BLI_float4x4.hh" +#include "BLI_math_vec_types.hh" + +BLI_CPP_TYPE_MAKE(bool, bool, CPPTypeFlags::BasicType) + +BLI_CPP_TYPE_MAKE(float, float, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(float2, blender::float2, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(float3, blender::float3, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(float4x4, blender::float4x4, CPPTypeFlags::BasicType) + +BLI_CPP_TYPE_MAKE(int32, int32_t, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(int8, int8_t, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(uint32, uint32_t, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(uint8, uint8_t, CPPTypeFlags::BasicType) + +BLI_CPP_TYPE_MAKE(ColorGeometry4f, blender::ColorGeometry4f, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(ColorGeometry4b, blender::ColorGeometry4b, CPPTypeFlags::BasicType) + +BLI_CPP_TYPE_MAKE(string, std::string, CPPTypeFlags::BasicType) diff --git a/source/blender/blenlib/tests/BLI_cpp_type_test.cc b/source/blender/blenlib/tests/BLI_cpp_type_test.cc new file mode 100644 index 00000000000..c7e6ed47b24 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_cpp_type_test.cc @@ -0,0 +1,326 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "BLI_cpp_type.hh" +#include "BLI_cpp_type_make.hh" + +namespace blender::tests { + +static const int default_constructed_value = 1; +static const int copy_constructed_value = 2; +static const int move_constructed_value = 3; +static const int copy_constructed_from_value = 4; +static const int move_constructed_from_value = 5; +static const int copy_assigned_value = 6; +static const int copy_assigned_from_value = 7; +static const int move_assigned_value = 8; +static const int move_assigned_from_value = 9; +static const int destructed_value = 10; + +struct TestType { + mutable volatile int value; + + TestType() + { + value = default_constructed_value; + } + + ~TestType() + { + value = destructed_value; + } + + TestType(const TestType &other) + { + value = copy_constructed_value; + other.value = copy_constructed_from_value; + } + + TestType(TestType &&other) noexcept + { + value = move_constructed_value; + other.value = move_constructed_from_value; + } + + TestType &operator=(const TestType &other) + { + value = copy_assigned_value; + other.value = copy_assigned_from_value; + return *this; + } + + TestType &operator=(TestType &&other) noexcept + { + value = move_assigned_value; + other.value = move_assigned_from_value; + return *this; + } + + friend std::ostream &operator<<(std::ostream &stream, const TestType &value) + { + stream << value.value; + return stream; + } + + friend bool operator==(const TestType &UNUSED(a), const TestType &UNUSED(b)) + { + return false; + } + + uint64_t hash() const + { + return 0; + } +}; + +} // namespace blender::tests + +BLI_CPP_TYPE_MAKE(TestType, blender::tests::TestType, CPPTypeFlags::BasicType) + +namespace blender::tests { + +static const CPPType &CPPType_TestType = CPPType::get(); + +TEST(cpp_type, Size) +{ + EXPECT_EQ(CPPType_TestType.size(), sizeof(TestType)); +} + +TEST(cpp_type, Alignment) +{ + EXPECT_EQ(CPPType_TestType.alignment(), alignof(TestType)); +} + +TEST(cpp_type, Is) +{ + EXPECT_TRUE(CPPType_TestType.is()); + EXPECT_FALSE(CPPType_TestType.is()); +} + +TEST(cpp_type, DefaultConstruction) +{ + int buffer[10] = {0}; + CPPType_TestType.default_construct((void *)buffer); + EXPECT_EQ(buffer[0], default_constructed_value); + EXPECT_EQ(buffer[1], 0); + CPPType_TestType.default_construct_n((void *)buffer, 3); + EXPECT_EQ(buffer[0], default_constructed_value); + EXPECT_EQ(buffer[1], default_constructed_value); + EXPECT_EQ(buffer[2], default_constructed_value); + EXPECT_EQ(buffer[3], 0); + CPPType_TestType.default_construct_indices((void *)buffer, {2, 5, 7}); + EXPECT_EQ(buffer[2], default_constructed_value); + EXPECT_EQ(buffer[4], 0); + EXPECT_EQ(buffer[5], default_constructed_value); + EXPECT_EQ(buffer[6], 0); + EXPECT_EQ(buffer[7], default_constructed_value); + EXPECT_EQ(buffer[8], 0); +} + +TEST(cpp_type, Destruct) +{ + int buffer[10] = {0}; + CPPType_TestType.destruct((void *)buffer); + EXPECT_EQ(buffer[0], destructed_value); + EXPECT_EQ(buffer[1], 0); + CPPType_TestType.destruct_n((void *)buffer, 3); + EXPECT_EQ(buffer[0], destructed_value); + EXPECT_EQ(buffer[1], destructed_value); + EXPECT_EQ(buffer[2], destructed_value); + EXPECT_EQ(buffer[3], 0); + CPPType_TestType.destruct_indices((void *)buffer, {2, 5, 7}); + EXPECT_EQ(buffer[2], destructed_value); + EXPECT_EQ(buffer[4], 0); + EXPECT_EQ(buffer[5], destructed_value); + EXPECT_EQ(buffer[6], 0); + EXPECT_EQ(buffer[7], destructed_value); + EXPECT_EQ(buffer[8], 0); +} + +TEST(cpp_type, CopyToUninitialized) +{ + int buffer1[10] = {0}; + int buffer2[10] = {0}; + CPPType_TestType.copy_construct((void *)buffer1, (void *)buffer2); + EXPECT_EQ(buffer1[0], copy_constructed_from_value); + EXPECT_EQ(buffer2[0], copy_constructed_value); + CPPType_TestType.copy_construct_n((void *)buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1[0], copy_constructed_from_value); + EXPECT_EQ(buffer2[0], copy_constructed_value); + EXPECT_EQ(buffer1[1], copy_constructed_from_value); + EXPECT_EQ(buffer2[1], copy_constructed_value); + EXPECT_EQ(buffer1[2], copy_constructed_from_value); + EXPECT_EQ(buffer2[2], copy_constructed_value); + EXPECT_EQ(buffer1[3], 0); + EXPECT_EQ(buffer2[3], 0); + CPPType_TestType.copy_construct_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); + EXPECT_EQ(buffer1[2], copy_constructed_from_value); + EXPECT_EQ(buffer2[2], copy_constructed_value); + EXPECT_EQ(buffer1[4], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer1[5], copy_constructed_from_value); + EXPECT_EQ(buffer2[5], copy_constructed_value); + EXPECT_EQ(buffer1[6], 0); + EXPECT_EQ(buffer2[6], 0); + EXPECT_EQ(buffer1[7], copy_constructed_from_value); + EXPECT_EQ(buffer2[7], copy_constructed_value); + EXPECT_EQ(buffer1[8], 0); + EXPECT_EQ(buffer2[8], 0); +} + +TEST(cpp_type, CopyToInitialized) +{ + int buffer1[10] = {0}; + int buffer2[10] = {0}; + CPPType_TestType.copy_assign((void *)buffer1, (void *)buffer2); + EXPECT_EQ(buffer1[0], copy_assigned_from_value); + EXPECT_EQ(buffer2[0], copy_assigned_value); + CPPType_TestType.copy_assign_n((void *)buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1[0], copy_assigned_from_value); + EXPECT_EQ(buffer2[0], copy_assigned_value); + EXPECT_EQ(buffer1[1], copy_assigned_from_value); + EXPECT_EQ(buffer2[1], copy_assigned_value); + EXPECT_EQ(buffer1[2], copy_assigned_from_value); + EXPECT_EQ(buffer2[2], copy_assigned_value); + EXPECT_EQ(buffer1[3], 0); + EXPECT_EQ(buffer2[3], 0); + CPPType_TestType.copy_assign_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); + EXPECT_EQ(buffer1[2], copy_assigned_from_value); + EXPECT_EQ(buffer2[2], copy_assigned_value); + EXPECT_EQ(buffer1[4], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer1[5], copy_assigned_from_value); + EXPECT_EQ(buffer2[5], copy_assigned_value); + EXPECT_EQ(buffer1[6], 0); + EXPECT_EQ(buffer2[6], 0); + EXPECT_EQ(buffer1[7], copy_assigned_from_value); + EXPECT_EQ(buffer2[7], copy_assigned_value); + EXPECT_EQ(buffer1[8], 0); + EXPECT_EQ(buffer2[8], 0); +} + +TEST(cpp_type, RelocateToUninitialized) +{ + int buffer1[10] = {0}; + int buffer2[10] = {0}; + CPPType_TestType.relocate_construct((void *)buffer1, (void *)buffer2); + EXPECT_EQ(buffer1[0], destructed_value); + EXPECT_EQ(buffer2[0], move_constructed_value); + CPPType_TestType.relocate_construct_n((void *)buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1[0], destructed_value); + EXPECT_EQ(buffer2[0], move_constructed_value); + EXPECT_EQ(buffer1[1], destructed_value); + EXPECT_EQ(buffer2[1], move_constructed_value); + EXPECT_EQ(buffer1[2], destructed_value); + EXPECT_EQ(buffer2[2], move_constructed_value); + EXPECT_EQ(buffer1[3], 0); + EXPECT_EQ(buffer2[3], 0); + CPPType_TestType.relocate_construct_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); + EXPECT_EQ(buffer1[2], destructed_value); + EXPECT_EQ(buffer2[2], move_constructed_value); + EXPECT_EQ(buffer1[4], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer1[5], destructed_value); + EXPECT_EQ(buffer2[5], move_constructed_value); + EXPECT_EQ(buffer1[6], 0); + EXPECT_EQ(buffer2[6], 0); + EXPECT_EQ(buffer1[7], destructed_value); + EXPECT_EQ(buffer2[7], move_constructed_value); + EXPECT_EQ(buffer1[8], 0); + EXPECT_EQ(buffer2[8], 0); +} + +TEST(cpp_type, RelocateToInitialized) +{ + int buffer1[10] = {0}; + int buffer2[10] = {0}; + CPPType_TestType.relocate_assign((void *)buffer1, (void *)buffer2); + EXPECT_EQ(buffer1[0], destructed_value); + EXPECT_EQ(buffer2[0], move_assigned_value); + CPPType_TestType.relocate_assign_n((void *)buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1[0], destructed_value); + EXPECT_EQ(buffer2[0], move_assigned_value); + EXPECT_EQ(buffer1[1], destructed_value); + EXPECT_EQ(buffer2[1], move_assigned_value); + EXPECT_EQ(buffer1[2], destructed_value); + EXPECT_EQ(buffer2[2], move_assigned_value); + EXPECT_EQ(buffer1[3], 0); + EXPECT_EQ(buffer2[3], 0); + CPPType_TestType.relocate_assign_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); + EXPECT_EQ(buffer1[2], destructed_value); + EXPECT_EQ(buffer2[2], move_assigned_value); + EXPECT_EQ(buffer1[4], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer1[5], destructed_value); + EXPECT_EQ(buffer2[5], move_assigned_value); + EXPECT_EQ(buffer1[6], 0); + EXPECT_EQ(buffer2[6], 0); + EXPECT_EQ(buffer1[7], destructed_value); + EXPECT_EQ(buffer2[7], move_assigned_value); + EXPECT_EQ(buffer1[8], 0); + EXPECT_EQ(buffer2[8], 0); +} + +TEST(cpp_type, FillInitialized) +{ + int buffer1 = 0; + int buffer2[10] = {0}; + CPPType_TestType.fill_assign_n((void *)&buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1, copy_assigned_from_value); + EXPECT_EQ(buffer2[0], copy_assigned_value); + EXPECT_EQ(buffer2[1], copy_assigned_value); + EXPECT_EQ(buffer2[2], copy_assigned_value); + EXPECT_EQ(buffer2[3], 0); + + buffer1 = 0; + CPPType_TestType.fill_assign_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8}); + EXPECT_EQ(buffer1, copy_assigned_from_value); + EXPECT_EQ(buffer2[0], copy_assigned_value); + EXPECT_EQ(buffer2[1], copy_assigned_value); + EXPECT_EQ(buffer2[2], copy_assigned_value); + EXPECT_EQ(buffer2[3], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer2[5], 0); + EXPECT_EQ(buffer2[6], copy_assigned_value); + EXPECT_EQ(buffer2[7], 0); + EXPECT_EQ(buffer2[8], copy_assigned_value); + EXPECT_EQ(buffer2[9], 0); +} + +TEST(cpp_type, FillUninitialized) +{ + int buffer1 = 0; + int buffer2[10] = {0}; + CPPType_TestType.fill_construct_n((void *)&buffer1, (void *)buffer2, 3); + EXPECT_EQ(buffer1, copy_constructed_from_value); + EXPECT_EQ(buffer2[0], copy_constructed_value); + EXPECT_EQ(buffer2[1], copy_constructed_value); + EXPECT_EQ(buffer2[2], copy_constructed_value); + EXPECT_EQ(buffer2[3], 0); + + buffer1 = 0; + CPPType_TestType.fill_construct_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8}); + EXPECT_EQ(buffer1, copy_constructed_from_value); + EXPECT_EQ(buffer2[0], copy_constructed_value); + EXPECT_EQ(buffer2[1], copy_constructed_value); + EXPECT_EQ(buffer2[2], copy_constructed_value); + EXPECT_EQ(buffer2[3], 0); + EXPECT_EQ(buffer2[4], 0); + EXPECT_EQ(buffer2[5], 0); + EXPECT_EQ(buffer2[6], copy_constructed_value); + EXPECT_EQ(buffer2[7], 0); + EXPECT_EQ(buffer2[8], copy_constructed_value); + EXPECT_EQ(buffer2[9], 0); +} + +TEST(cpp_type, DebugPrint) +{ + int value = 42; + std::stringstream ss; + CPPType::get().print((void *)&value, ss); + std::string text = ss.str(); + EXPECT_EQ(text, "42"); +} + +} // namespace blender::tests diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 77cd5d9221f..28efc5be2e9 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -36,7 +36,6 @@ namespace blender::ed::geometry { -using fn::CPPType; using fn::GArray; using fn::GVArray; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index ae57a462242..06fdeabf3e1 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -69,7 +69,6 @@ bool CURVES_SCULPT_mode_poll_view3d(bContext *C) namespace blender::ed::sculpt_paint { using blender::bke::CurvesGeometry; -using blender::fn::CPPType; /* -------------------------------------------------------------------- */ /** \name * SCULPT_CURVES_OT_brush_stroke diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index e221fac5ef9..b8d8335d47c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -73,7 +73,6 @@ #include "node_intern.hh" /* own include */ -using blender::fn::CPPType; using blender::fn::FieldCPPType; using blender::fn::FieldInput; using blender::fn::GField; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index 964738ff2c1..19fe61f0ed3 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -5,6 +5,7 @@ #include "MEM_guardedalloc.h" #include "BLI_color.hh" +#include "BLI_cpp_type.hh" #include "BLI_hash.hh" #include "BLI_math_vec_types.hh" #include "BLI_string.h" @@ -12,14 +13,12 @@ #include "BKE_geometry_set.hh" -#include "FN_cpp_type.hh" - #include "spreadsheet_column.hh" #include "spreadsheet_column_values.hh" namespace blender::ed::spreadsheet { -eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type) +eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type) { if (type.is()) { return SPREADSHEET_VALUE_TYPE_BOOL; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh index 454518016bc..f4d07255e2d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh @@ -12,7 +12,7 @@ namespace blender::ed::spreadsheet { struct CellDrawParams; -eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type); +eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type); /** * This represents a column in a spreadsheet. It has a name and provides a value for all the cells diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 55432003010..eef5b1e3ea6 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -24,8 +24,6 @@ set(SRC intern/multi_function_procedure_executor.cc intern/multi_function_procedure_optimization.cc - FN_cpp_type.hh - FN_cpp_type_make.hh FN_field.hh FN_field_cpp_type.hh FN_generic_array.hh @@ -72,7 +70,6 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC - tests/FN_cpp_type_test.cc tests/FN_field_test.cc tests/FN_generic_array_test.cc tests/FN_generic_span_test.cc diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh deleted file mode 100644 index 420e2a8d9a9..00000000000 --- a/source/blender/functions/FN_cpp_type.hh +++ /dev/null @@ -1,635 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup fn - * - * The `CPPType` class is the core of a runtime-type-system. It allows working with arbitrary C++ - * types in a generic way. An instance of `CPPType` wraps exactly one type like `int` or - * `std::string`. - * - * 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: - * - default_construct(void *ptr): - * Constructs a single instance of that type at the given pointer. - * - default_construct_n(void *ptr, int64_t n): - * Constructs n instances of that type in an array that starts at the given pointer. - * - default_construct_indices(void *ptr, IndexMask mask): - * Constructs multiple instances of that type in an array that starts at the given pointer. - * Only the indices referenced by `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 `default_construct` 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_hash.hh" -#include "BLI_index_mask.hh" -#include "BLI_math_base.h" -#include "BLI_string_ref.hh" -#include "BLI_utility_mixins.hh" - -/** - * Different types support different features. Features like copy constructability can be detected - * automatically easily. For some features this is harder as of C++17. Those have flags in this - * enum and need to be determined by the programmer. - */ -enum class CPPTypeFlags { - None = 0, - Hashable = 1 << 0, - Printable = 1 << 1, - EqualityComparable = 1 << 2, - - BasicType = Hashable | Printable | EqualityComparable, -}; -ENUM_OPERATORS(CPPTypeFlags, CPPTypeFlags::EqualityComparable) - -namespace blender::fn { - -/** Utility class to pass template parameters to constructor of `CPPType`. */ -template struct CPPTypeParam { -}; - -class CPPType : NonCopyable, NonMovable { - private: - int64_t size_ = 0; - int64_t alignment_ = 0; - uintptr_t alignment_mask_ = 0; - bool is_trivial_ = false; - bool is_trivially_destructible_ = false; - bool has_special_member_functions_ = false; - - void (*default_construct_)(void *ptr) = nullptr; - void (*default_construct_indices_)(void *ptr, IndexMask mask) = nullptr; - - void (*destruct_)(void *ptr) = nullptr; - void (*destruct_indices_)(void *ptr, IndexMask mask) = nullptr; - - void (*copy_assign_)(const void *src, void *dst) = nullptr; - void (*copy_assign_indices_)(const void *src, void *dst, IndexMask mask) = nullptr; - - void (*copy_construct_)(const void *src, void *dst) = nullptr; - void (*copy_construct_indices_)(const void *src, void *dst, IndexMask mask) = nullptr; - - void (*move_assign_)(void *src, void *dst) = nullptr; - void (*move_assign_indices_)(void *src, void *dst, IndexMask mask) = nullptr; - - void (*move_construct_)(void *src, void *dst) = nullptr; - void (*move_construct_indices_)(void *src, void *dst, IndexMask mask) = nullptr; - - void (*relocate_assign_)(void *src, void *dst) = nullptr; - void (*relocate_assign_indices_)(void *src, void *dst, IndexMask mask) = nullptr; - - void (*relocate_construct_)(void *src, void *dst) = nullptr; - void (*relocate_construct_indices_)(void *src, void *dst, IndexMask mask) = nullptr; - - void (*fill_assign_indices_)(const void *value, void *dst, IndexMask mask) = nullptr; - - void (*fill_construct_indices_)(const void *value, void *dst, IndexMask mask) = nullptr; - - void (*print_)(const void *value, std::stringstream &ss) = nullptr; - bool (*is_equal_)(const void *a, const void *b) = nullptr; - uint64_t (*hash_)(const void *value) = nullptr; - - const void *default_value_ = nullptr; - std::string debug_name_; - - public: - template CPPType(CPPTypeParam, StringRef debug_name); - virtual ~CPPType() = default; - - /** - * 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); - } - - /** - * Get the `CPPType` that corresponds to a specific static type. - * This only works for types that actually implement the template specialization using - * `MAKE_CPP_TYPE`. - */ - template static const CPPType &get() - { - return CPPType::get_impl>(); - } - template static const CPPType &get_impl(); - - /** - * Returns the name of the type for debugging purposes. This name should not be used as - * identifier. - */ - StringRefNull name() const - { - return debug_name_; - } - - /** - * Required memory in bytes for an instance of this type. - * - * C++ equivalent: - * `sizeof(T);` - */ - int64_t size() const - { - return size_; - } - - /** - * Required memory alignment for an instance of this type. - * - * C++ equivalent: - * alignof(T); - */ - int64_t alignment() const - { - return 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_v; - */ - bool is_trivially_destructible() const - { - return is_trivially_destructible_; - } - - /** - * When true, the value is like a normal C type, it can be copied around with #memcpy and does - * not have to be destructed. - * - * C++ equivalent: - * std::is_trivial_v; - */ - bool is_trivial() const - { - return is_trivial_; - } - - bool is_default_constructible() const - { - return default_construct_ != nullptr; - } - - bool is_copy_constructible() const - { - return copy_assign_ != nullptr; - } - - bool is_move_constructible() const - { - return move_assign_ != nullptr; - } - - bool is_destructible() const - { - return destruct_ != nullptr; - } - - bool is_copy_assignable() const - { - return copy_assign_ != nullptr; - } - - bool is_move_assignable() const - { - return copy_construct_ != nullptr; - } - - bool is_printable() const - { - return print_ != nullptr; - } - - bool is_equality_comparable() const - { - return is_equal_ != nullptr; - } - - bool is_hashable() const - { - return hash_ != nullptr; - } - - /** - * Returns true, when the type has the following functions: - * - Default constructor. - * - Copy constructor. - * - Move constructor. - * - Copy assignment operator. - * - Move assignment operator. - * - Destructor. - */ - bool has_special_member_functions() const - { - return has_special_member_functions_; - } - - /** - * Returns true, when the given pointer fulfills the alignment requirement of this type. - */ - bool pointer_has_valid_alignment(const void *ptr) const - { - return ((uintptr_t)ptr & 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 default_construct(void *ptr) const - { - BLI_assert(this->pointer_can_point_to_instance(ptr)); - - default_construct_(ptr); - } - - void default_construct_n(void *ptr, int64_t n) const - { - this->default_construct_indices(ptr, IndexMask(n)); - } - - void default_construct_indices(void *ptr, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr)); - - default_construct_indices_(ptr, 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)); - - destruct_(ptr); - } - - void destruct_n(void *ptr, int64_t n) const - { - this->destruct_indices(ptr, IndexMask(n)); - } - - void destruct_indices(void *ptr, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr)); - - destruct_indices_(ptr, mask); - } - - /** - * Copy an instance of this type from src to dst. - * - * C++ equivalent: - * dst = src; - */ - void copy_assign(const void *src, void *dst) const - { - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - copy_assign_(src, dst); - } - - void copy_assign_n(const void *src, void *dst, int64_t n) const - { - this->copy_assign_indices(src, dst, IndexMask(n)); - } - - void copy_assign_indices(const void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - copy_assign_indices_(src, dst, 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_construct(const void *src, void *dst) const - { - BLI_assert(src != dst || is_trivial_); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - copy_construct_(src, dst); - } - - void copy_construct_n(const void *src, void *dst, int64_t n) const - { - this->copy_construct_indices(src, dst, IndexMask(n)); - } - - void copy_construct_indices(const void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - copy_construct_indices_(src, dst, mask); - } - - /** - * Move an instance of this type from src to dst. - * - * The memory pointed to by dst should be initialized. - * - * C++ equivalent: - * dst = std::move(src); - */ - void move_assign(void *src, void *dst) const - { - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - move_assign_(src, dst); - } - - void move_assign_n(void *src, void *dst, int64_t n) const - { - this->move_assign_indices(src, dst, IndexMask(n)); - } - - void move_assign_indices(void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - move_assign_indices_(src, dst, mask); - } - - /** - * Move an instance of this type from src to dst. - * - * The memory pointed to by dst should be uninitialized. - * - * C++ equivalent: - * new (dst) T(std::move(src)); - */ - void move_construct(void *src, void *dst) const - { - BLI_assert(src != dst || is_trivial_); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - move_construct_(src, dst); - } - - void move_construct_n(void *src, void *dst, int64_t n) const - { - this->move_construct_indices(src, dst, IndexMask(n)); - } - - void move_construct_indices(void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - move_construct_indices_(src, dst, 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_assign(void *src, void *dst) const - { - BLI_assert(src != dst || is_trivial_); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - relocate_assign_(src, dst); - } - - void relocate_assign_n(void *src, void *dst, int64_t n) const - { - this->relocate_assign_indices(src, dst, IndexMask(n)); - } - - void relocate_assign_indices(void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - relocate_assign_indices_(src, dst, 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_construct(void *src, void *dst) const - { - BLI_assert(src != dst || is_trivial_); - BLI_assert(this->pointer_can_point_to_instance(src)); - BLI_assert(this->pointer_can_point_to_instance(dst)); - - relocate_construct_(src, dst); - } - - void relocate_construct_n(void *src, void *dst, int64_t n) const - { - this->relocate_construct_indices(src, dst, IndexMask(n)); - } - - void relocate_construct_indices(void *src, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || src != dst); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - relocate_construct_indices_(src, dst, 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_assign_n(const void *value, void *dst, int64_t n) const - { - this->fill_assign_indices(value, dst, IndexMask(n)); - } - - void fill_assign_indices(const void *value, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - fill_assign_indices_(value, dst, 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_construct_n(const void *value, void *dst, int64_t n) const - { - this->fill_construct_indices(value, dst, IndexMask(n)); - } - - void fill_construct_indices(const void *value, void *dst, IndexMask mask) const - { - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value)); - BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst)); - - fill_construct_indices_(value, dst, mask); - } - - void print(const void *value, std::stringstream &ss) const - { - BLI_assert(this->pointer_can_point_to_instance(value)); - print_(value, ss); - } - - std::string to_string(const void *value) const - { - std::stringstream ss; - this->print(value, ss); - return ss.str(); - } - - void print_or_default(const void *value, std::stringstream &ss, StringRef default_value) const - { - if (this->is_printable()) { - this->print(value, ss); - } - else { - ss << default_value; - } - } - - bool is_equal(const void *a, const void *b) const - { - BLI_assert(this->pointer_can_point_to_instance(a)); - BLI_assert(this->pointer_can_point_to_instance(b)); - return is_equal_(a, b); - } - - bool is_equal_or_false(const void *a, const void *b) const - { - if (this->is_equality_comparable()) { - return this->is_equal(a, b); - } - return false; - } - - uint64_t hash(const void *value) const - { - BLI_assert(this->pointer_can_point_to_instance(value)); - return hash_(value); - } - - uint64_t hash_or_fallback(const void *value, uint64_t fallback_hash) const - { - if (this->is_hashable()) { - return this->hash(value); - } - return fallback_hash; - } - - /** - * 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 default_value_; - } - - uint64_t hash() const - { - return get_default_hash(this); - } - - void (*destruct_fn() const)(void *) - { - return destruct_; - } - - template bool is() const - { - return this == &CPPType::get>(); - } -}; - -} // namespace blender::fn - -/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */ -#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \ - blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name((type).size(), \ - (type).alignment()); \ - void *variable_name = stack_buffer_for_##variable_name.buffer(); diff --git a/source/blender/functions/FN_cpp_type_make.hh b/source/blender/functions/FN_cpp_type_make.hh deleted file mode 100644 index ac498e40fe3..00000000000 --- a/source/blender/functions/FN_cpp_type_make.hh +++ /dev/null @@ -1,251 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup fn - */ - -#include "BLI_utildefines.h" -#include "FN_cpp_type.hh" - -namespace blender::fn::cpp_type_util { - -template void default_construct_cb(void *ptr) -{ - new (ptr) T; -} -template void default_construct_indices_cb(void *ptr, IndexMask mask) -{ - mask.foreach_index([&](int64_t i) { new (static_cast(ptr) + i) T; }); -} - -template void destruct_cb(void *ptr) -{ - (static_cast(ptr))->~T(); -} -template void destruct_indices_cb(void *ptr, IndexMask mask) -{ - T *ptr_ = static_cast(ptr); - mask.foreach_index([&](int64_t i) { ptr_[i].~T(); }); -} - -template void copy_assign_cb(const void *src, void *dst) -{ - *static_cast(dst) = *static_cast(src); -} -template void copy_assign_indices_cb(const void *src, void *dst, IndexMask mask) -{ - const T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { dst_[i] = src_[i]; }); -} - -template void copy_construct_cb(const void *src, void *dst) -{ - blender::uninitialized_copy_n(static_cast(src), 1, static_cast(dst)); -} -template void copy_construct_indices_cb(const void *src, void *dst, IndexMask mask) -{ - const T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { new (dst_ + i) T(src_[i]); }); -} - -template void move_assign_cb(void *src, void *dst) -{ - blender::initialized_move_n(static_cast(src), 1, static_cast(dst)); -} -template void move_assign_indices_cb(void *src, void *dst, IndexMask mask) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { dst_[i] = std::move(src_[i]); }); -} - -template void move_construct_cb(void *src, void *dst) -{ - blender::uninitialized_move_n(static_cast(src), 1, static_cast(dst)); -} -template void move_construct_indices_cb(void *src, void *dst, IndexMask mask) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { new (dst_ + i) T(std::move(src_[i])); }); -} - -template void relocate_assign_cb(void *src, void *dst) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - *dst_ = std::move(*src_); - src_->~T(); -} -template void relocate_assign_indices_cb(void *src, void *dst, IndexMask mask) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { - dst_[i] = std::move(src_[i]); - src_[i].~T(); - }); -} - -template void relocate_construct_cb(void *src, void *dst) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - new (dst_) T(std::move(*src_)); - src_->~T(); -} -template void relocate_construct_indices_cb(void *src, void *dst, IndexMask mask) -{ - T *src_ = static_cast(src); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { - new (dst_ + i) T(std::move(src_[i])); - src_[i].~T(); - }); -} - -template void fill_assign_cb(const void *value, void *dst, int64_t n) -{ - const T &value_ = *static_cast(value); - T *dst_ = static_cast(dst); - - for (int64_t i = 0; i < n; i++) { - dst_[i] = value_; - } -} -template void fill_assign_indices_cb(const void *value, void *dst, IndexMask mask) -{ - const T &value_ = *static_cast(value); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { dst_[i] = value_; }); -} - -template void fill_construct_cb(const void *value, void *dst, int64_t n) -{ - const T &value_ = *static_cast(value); - T *dst_ = static_cast(dst); - - for (int64_t i = 0; i < n; i++) { - new (dst_ + i) T(value_); - } -} -template void fill_construct_indices_cb(const void *value, void *dst, IndexMask mask) -{ - const T &value_ = *static_cast(value); - T *dst_ = static_cast(dst); - - mask.foreach_index([&](int64_t i) { new (dst_ + i) T(value_); }); -} - -template void print_cb(const void *value, std::stringstream &ss) -{ - const T &value_ = *static_cast(value); - ss << value_; -} - -template bool is_equal_cb(const void *a, const void *b) -{ - const T &a_ = *static_cast(a); - const T &b_ = *static_cast(b); - return a_ == b_; -} - -template uint64_t hash_cb(const void *value) -{ - const T &value_ = *static_cast(value); - return get_default_hash(value_); -} - -} // namespace blender::fn::cpp_type_util - -namespace blender::fn { - -template -CPPType::CPPType(CPPTypeParam /* unused */, StringRef debug_name) -{ - using namespace cpp_type_util; - - debug_name_ = debug_name; - size_ = (int64_t)sizeof(T); - alignment_ = (int64_t)alignof(T); - is_trivial_ = std::is_trivial_v; - is_trivially_destructible_ = std::is_trivially_destructible_v; - if constexpr (std::is_default_constructible_v) { - default_construct_ = default_construct_cb; - default_construct_indices_ = default_construct_indices_cb; - static T default_value; - default_value_ = (void *)&default_value; - } - if constexpr (std::is_destructible_v) { - destruct_ = destruct_cb; - destruct_indices_ = destruct_indices_cb; - } - if constexpr (std::is_copy_assignable_v) { - copy_assign_ = copy_assign_cb; - copy_assign_indices_ = copy_assign_indices_cb; - } - if constexpr (std::is_copy_constructible_v) { - copy_construct_ = copy_construct_cb; - copy_construct_indices_ = copy_construct_indices_cb; - } - if constexpr (std::is_move_assignable_v) { - move_assign_ = move_assign_cb; - move_assign_indices_ = move_assign_indices_cb; - } - if constexpr (std::is_move_constructible_v) { - move_construct_ = move_construct_cb; - move_construct_indices_ = move_construct_indices_cb; - } - if constexpr (std::is_destructible_v) { - if constexpr (std::is_move_assignable_v) { - relocate_assign_ = relocate_assign_cb; - relocate_assign_indices_ = relocate_assign_indices_cb; - } - if constexpr (std::is_move_constructible_v) { - relocate_construct_ = relocate_construct_cb; - relocate_construct_indices_ = relocate_construct_indices_cb; - } - } - if constexpr (std::is_copy_assignable_v) { - fill_assign_indices_ = fill_assign_indices_cb; - } - if constexpr (std::is_copy_constructible_v) { - fill_construct_indices_ = fill_construct_indices_cb; - } - if constexpr ((bool)(Flags & CPPTypeFlags::Hashable)) { - hash_ = hash_cb; - } - if constexpr ((bool)(Flags & CPPTypeFlags::Printable)) { - print_ = print_cb; - } - if constexpr ((bool)(Flags & CPPTypeFlags::EqualityComparable)) { - is_equal_ = is_equal_cb; - } - - alignment_mask_ = (uintptr_t)alignment_ - (uintptr_t)1; - has_special_member_functions_ = (default_construct_ && copy_construct_ && copy_assign_ && - move_construct_ && move_assign_ && destruct_); -} - -} // namespace blender::fn - -#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME, FLAGS) \ - template<> const blender::fn::CPPType &blender::fn::CPPType::get_impl() \ - { \ - static CPPType cpp_type{blender::fn::CPPTypeParam(), \ - STRINGIFY(IDENTIFIER)}; \ - return cpp_type; \ - } diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 2cba833ce64..957b395e633 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -119,7 +119,7 @@ template class GFieldBase { return get_default_hash_2(*node_, node_output_index_); } - const fn::CPPType &cpp_type() const + const CPPType &cpp_type() const { return node_->output_cpp_type(node_output_index_); } @@ -476,13 +476,13 @@ template T evaluate_constant_field(const Field &field) return value; } +GField make_constant_field(const CPPType &type, const void *value); + template Field make_constant_field(T value) { return make_constant_field(CPPType::get(), &value); } -GField make_constant_field(const CPPType &type, const void *value); - /** * If the field depends on some input, the same field is returned. * Otherwise the field is evaluated and a new field is created that just computes this constant. diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index 24477246582..63a648f3202 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -6,7 +6,7 @@ * \ingroup fn */ -#include "FN_cpp_type_make.hh" +#include "BLI_cpp_type_make.hh" #include "FN_field.hh" namespace blender::fn { @@ -127,16 +127,14 @@ class ValueOrFieldCPPType : public CPPType { } // namespace blender::fn #define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \ - template<> \ - const blender::fn::CPPType &blender::fn::CPPType::get_impl>() \ + template<> const blender::CPPType &blender::CPPType::get_impl>() \ { \ static blender::fn::FieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam>(), STRINGIFY(DEBUG_NAME)}; \ return cpp_type; \ } \ template<> \ - const blender::fn::CPPType & \ - blender::fn::CPPType::get_impl>() \ + const blender::CPPType &blender::CPPType::get_impl>() \ { \ static blender::fn::ValueOrFieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam>(), \ diff --git a/source/blender/functions/FN_generic_array.hh b/source/blender/functions/FN_generic_array.hh index 4bd0c38aa42..c5388d27585 100644 --- a/source/blender/functions/FN_generic_array.hh +++ b/source/blender/functions/FN_generic_array.hh @@ -14,8 +14,8 @@ */ #include "BLI_allocator.hh" +#include "BLI_cpp_type.hh" -#include "FN_cpp_type.hh" #include "FN_generic_span.hh" namespace blender::fn { diff --git a/source/blender/functions/FN_generic_pointer.hh b/source/blender/functions/FN_generic_pointer.hh index a1fb16b5ab2..382d882e3f7 100644 --- a/source/blender/functions/FN_generic_pointer.hh +++ b/source/blender/functions/FN_generic_pointer.hh @@ -2,7 +2,7 @@ #pragma once -#include "FN_cpp_type.hh" +#include "BLI_cpp_type.hh" namespace blender::fn { diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh index 2d3bfa55787..c79cece138f 100644 --- a/source/blender/functions/FN_generic_span.hh +++ b/source/blender/functions/FN_generic_span.hh @@ -6,10 +6,9 @@ * \ingroup fn */ +#include "BLI_cpp_type.hh" #include "BLI_span.hh" -#include "FN_cpp_type.hh" - namespace blender::fn { /** diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh index cca6955aeb0..edeb1fed27e 100644 --- a/source/blender/functions/FN_multi_function.hh +++ b/source/blender/functions/FN_multi_function.hh @@ -154,7 +154,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask } namespace multi_function_types { -using fn::CPPType; using fn::GMutableSpan; using fn::GSpan; using fn::MFContext; diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh index a0ded253d26..d63e0faaca5 100644 --- a/source/blender/functions/FN_multi_function_data_type.hh +++ b/source/blender/functions/FN_multi_function_data_type.hh @@ -10,7 +10,7 @@ * is possible when necessary. */ -#include "FN_cpp_type.hh" +#include "BLI_cpp_type.hh" namespace blender::fn { diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index 5606f660237..a2adc2ea8b6 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -1,38 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "FN_cpp_type_make.hh" -#include "FN_field_cpp_type.hh" - #include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" #include "BLI_float4x4.hh" #include "BLI_math_vec_types.hh" -namespace blender::fn { - -MAKE_CPP_TYPE(bool, bool, CPPTypeFlags::BasicType) - -MAKE_CPP_TYPE(float, float, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(float2, blender::float2, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(float3, blender::float3, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(float4x4, blender::float4x4, CPPTypeFlags::BasicType) - -MAKE_CPP_TYPE(int32, int32_t, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(int8, int8_t, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(uint32, uint32_t, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(uint8, uint8_t, CPPTypeFlags::BasicType) - -MAKE_CPP_TYPE(ColorGeometry4f, blender::ColorGeometry4f, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(ColorGeometry4b, blender::ColorGeometry4b, CPPTypeFlags::BasicType) - -MAKE_CPP_TYPE(string, std::string, CPPTypeFlags::BasicType) +#include "FN_field_cpp_type.hh" MAKE_FIELD_CPP_TYPE(FloatField, float); -MAKE_FIELD_CPP_TYPE(Float2Field, float2); -MAKE_FIELD_CPP_TYPE(Float3Field, float3); +MAKE_FIELD_CPP_TYPE(Float2Field, blender::float2); +MAKE_FIELD_CPP_TYPE(Float3Field, blender::float3); MAKE_FIELD_CPP_TYPE(ColorGeometry4fField, blender::ColorGeometry4f); MAKE_FIELD_CPP_TYPE(BoolField, bool); MAKE_FIELD_CPP_TYPE(Int8Field, int8_t); MAKE_FIELD_CPP_TYPE(Int32Field, int32_t); MAKE_FIELD_CPP_TYPE(StringField, std::string); - -} // namespace blender::fn diff --git a/source/blender/functions/tests/FN_cpp_type_test.cc b/source/blender/functions/tests/FN_cpp_type_test.cc deleted file mode 100644 index 6d9310874f5..00000000000 --- a/source/blender/functions/tests/FN_cpp_type_test.cc +++ /dev/null @@ -1,326 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include "testing/testing.h" - -#include "FN_cpp_type.hh" -#include "FN_cpp_type_make.hh" - -namespace blender::fn::tests { - -static const int default_constructed_value = 1; -static const int copy_constructed_value = 2; -static const int move_constructed_value = 3; -static const int copy_constructed_from_value = 4; -static const int move_constructed_from_value = 5; -static const int copy_assigned_value = 6; -static const int copy_assigned_from_value = 7; -static const int move_assigned_value = 8; -static const int move_assigned_from_value = 9; -static const int destructed_value = 10; - -struct TestType { - mutable volatile int value; - - TestType() - { - value = default_constructed_value; - } - - ~TestType() - { - value = destructed_value; - } - - TestType(const TestType &other) - { - value = copy_constructed_value; - other.value = copy_constructed_from_value; - } - - TestType(TestType &&other) noexcept - { - value = move_constructed_value; - other.value = move_constructed_from_value; - } - - TestType &operator=(const TestType &other) - { - value = copy_assigned_value; - other.value = copy_assigned_from_value; - return *this; - } - - TestType &operator=(TestType &&other) noexcept - { - value = move_assigned_value; - other.value = move_assigned_from_value; - return *this; - } - - friend std::ostream &operator<<(std::ostream &stream, const TestType &value) - { - stream << value.value; - return stream; - } - - friend bool operator==(const TestType &UNUSED(a), const TestType &UNUSED(b)) - { - return false; - } - - uint64_t hash() const - { - return 0; - } -}; - -} // namespace blender::fn::tests - -MAKE_CPP_TYPE(TestType, blender::fn::tests::TestType, CPPTypeFlags::BasicType) - -namespace blender::fn::tests { - -static const CPPType &CPPType_TestType = CPPType::get(); - -TEST(cpp_type, Size) -{ - EXPECT_EQ(CPPType_TestType.size(), sizeof(TestType)); -} - -TEST(cpp_type, Alignment) -{ - EXPECT_EQ(CPPType_TestType.alignment(), alignof(TestType)); -} - -TEST(cpp_type, Is) -{ - EXPECT_TRUE(CPPType_TestType.is()); - EXPECT_FALSE(CPPType_TestType.is()); -} - -TEST(cpp_type, DefaultConstruction) -{ - int buffer[10] = {0}; - CPPType_TestType.default_construct((void *)buffer); - EXPECT_EQ(buffer[0], default_constructed_value); - EXPECT_EQ(buffer[1], 0); - CPPType_TestType.default_construct_n((void *)buffer, 3); - EXPECT_EQ(buffer[0], default_constructed_value); - EXPECT_EQ(buffer[1], default_constructed_value); - EXPECT_EQ(buffer[2], default_constructed_value); - EXPECT_EQ(buffer[3], 0); - CPPType_TestType.default_construct_indices((void *)buffer, {2, 5, 7}); - EXPECT_EQ(buffer[2], default_constructed_value); - EXPECT_EQ(buffer[4], 0); - EXPECT_EQ(buffer[5], default_constructed_value); - EXPECT_EQ(buffer[6], 0); - EXPECT_EQ(buffer[7], default_constructed_value); - EXPECT_EQ(buffer[8], 0); -} - -TEST(cpp_type, Destruct) -{ - int buffer[10] = {0}; - CPPType_TestType.destruct((void *)buffer); - EXPECT_EQ(buffer[0], destructed_value); - EXPECT_EQ(buffer[1], 0); - CPPType_TestType.destruct_n((void *)buffer, 3); - EXPECT_EQ(buffer[0], destructed_value); - EXPECT_EQ(buffer[1], destructed_value); - EXPECT_EQ(buffer[2], destructed_value); - EXPECT_EQ(buffer[3], 0); - CPPType_TestType.destruct_indices((void *)buffer, {2, 5, 7}); - EXPECT_EQ(buffer[2], destructed_value); - EXPECT_EQ(buffer[4], 0); - EXPECT_EQ(buffer[5], destructed_value); - EXPECT_EQ(buffer[6], 0); - EXPECT_EQ(buffer[7], destructed_value); - EXPECT_EQ(buffer[8], 0); -} - -TEST(cpp_type, CopyToUninitialized) -{ - int buffer1[10] = {0}; - int buffer2[10] = {0}; - CPPType_TestType.copy_construct((void *)buffer1, (void *)buffer2); - EXPECT_EQ(buffer1[0], copy_constructed_from_value); - EXPECT_EQ(buffer2[0], copy_constructed_value); - CPPType_TestType.copy_construct_n((void *)buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1[0], copy_constructed_from_value); - EXPECT_EQ(buffer2[0], copy_constructed_value); - EXPECT_EQ(buffer1[1], copy_constructed_from_value); - EXPECT_EQ(buffer2[1], copy_constructed_value); - EXPECT_EQ(buffer1[2], copy_constructed_from_value); - EXPECT_EQ(buffer2[2], copy_constructed_value); - EXPECT_EQ(buffer1[3], 0); - EXPECT_EQ(buffer2[3], 0); - CPPType_TestType.copy_construct_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); - EXPECT_EQ(buffer1[2], copy_constructed_from_value); - EXPECT_EQ(buffer2[2], copy_constructed_value); - EXPECT_EQ(buffer1[4], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer1[5], copy_constructed_from_value); - EXPECT_EQ(buffer2[5], copy_constructed_value); - EXPECT_EQ(buffer1[6], 0); - EXPECT_EQ(buffer2[6], 0); - EXPECT_EQ(buffer1[7], copy_constructed_from_value); - EXPECT_EQ(buffer2[7], copy_constructed_value); - EXPECT_EQ(buffer1[8], 0); - EXPECT_EQ(buffer2[8], 0); -} - -TEST(cpp_type, CopyToInitialized) -{ - int buffer1[10] = {0}; - int buffer2[10] = {0}; - CPPType_TestType.copy_assign((void *)buffer1, (void *)buffer2); - EXPECT_EQ(buffer1[0], copy_assigned_from_value); - EXPECT_EQ(buffer2[0], copy_assigned_value); - CPPType_TestType.copy_assign_n((void *)buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1[0], copy_assigned_from_value); - EXPECT_EQ(buffer2[0], copy_assigned_value); - EXPECT_EQ(buffer1[1], copy_assigned_from_value); - EXPECT_EQ(buffer2[1], copy_assigned_value); - EXPECT_EQ(buffer1[2], copy_assigned_from_value); - EXPECT_EQ(buffer2[2], copy_assigned_value); - EXPECT_EQ(buffer1[3], 0); - EXPECT_EQ(buffer2[3], 0); - CPPType_TestType.copy_assign_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); - EXPECT_EQ(buffer1[2], copy_assigned_from_value); - EXPECT_EQ(buffer2[2], copy_assigned_value); - EXPECT_EQ(buffer1[4], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer1[5], copy_assigned_from_value); - EXPECT_EQ(buffer2[5], copy_assigned_value); - EXPECT_EQ(buffer1[6], 0); - EXPECT_EQ(buffer2[6], 0); - EXPECT_EQ(buffer1[7], copy_assigned_from_value); - EXPECT_EQ(buffer2[7], copy_assigned_value); - EXPECT_EQ(buffer1[8], 0); - EXPECT_EQ(buffer2[8], 0); -} - -TEST(cpp_type, RelocateToUninitialized) -{ - int buffer1[10] = {0}; - int buffer2[10] = {0}; - CPPType_TestType.relocate_construct((void *)buffer1, (void *)buffer2); - EXPECT_EQ(buffer1[0], destructed_value); - EXPECT_EQ(buffer2[0], move_constructed_value); - CPPType_TestType.relocate_construct_n((void *)buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1[0], destructed_value); - EXPECT_EQ(buffer2[0], move_constructed_value); - EXPECT_EQ(buffer1[1], destructed_value); - EXPECT_EQ(buffer2[1], move_constructed_value); - EXPECT_EQ(buffer1[2], destructed_value); - EXPECT_EQ(buffer2[2], move_constructed_value); - EXPECT_EQ(buffer1[3], 0); - EXPECT_EQ(buffer2[3], 0); - CPPType_TestType.relocate_construct_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); - EXPECT_EQ(buffer1[2], destructed_value); - EXPECT_EQ(buffer2[2], move_constructed_value); - EXPECT_EQ(buffer1[4], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer1[5], destructed_value); - EXPECT_EQ(buffer2[5], move_constructed_value); - EXPECT_EQ(buffer1[6], 0); - EXPECT_EQ(buffer2[6], 0); - EXPECT_EQ(buffer1[7], destructed_value); - EXPECT_EQ(buffer2[7], move_constructed_value); - EXPECT_EQ(buffer1[8], 0); - EXPECT_EQ(buffer2[8], 0); -} - -TEST(cpp_type, RelocateToInitialized) -{ - int buffer1[10] = {0}; - int buffer2[10] = {0}; - CPPType_TestType.relocate_assign((void *)buffer1, (void *)buffer2); - EXPECT_EQ(buffer1[0], destructed_value); - EXPECT_EQ(buffer2[0], move_assigned_value); - CPPType_TestType.relocate_assign_n((void *)buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1[0], destructed_value); - EXPECT_EQ(buffer2[0], move_assigned_value); - EXPECT_EQ(buffer1[1], destructed_value); - EXPECT_EQ(buffer2[1], move_assigned_value); - EXPECT_EQ(buffer1[2], destructed_value); - EXPECT_EQ(buffer2[2], move_assigned_value); - EXPECT_EQ(buffer1[3], 0); - EXPECT_EQ(buffer2[3], 0); - CPPType_TestType.relocate_assign_indices((void *)buffer1, (void *)buffer2, {2, 5, 7}); - EXPECT_EQ(buffer1[2], destructed_value); - EXPECT_EQ(buffer2[2], move_assigned_value); - EXPECT_EQ(buffer1[4], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer1[5], destructed_value); - EXPECT_EQ(buffer2[5], move_assigned_value); - EXPECT_EQ(buffer1[6], 0); - EXPECT_EQ(buffer2[6], 0); - EXPECT_EQ(buffer1[7], destructed_value); - EXPECT_EQ(buffer2[7], move_assigned_value); - EXPECT_EQ(buffer1[8], 0); - EXPECT_EQ(buffer2[8], 0); -} - -TEST(cpp_type, FillInitialized) -{ - int buffer1 = 0; - int buffer2[10] = {0}; - CPPType_TestType.fill_assign_n((void *)&buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1, copy_assigned_from_value); - EXPECT_EQ(buffer2[0], copy_assigned_value); - EXPECT_EQ(buffer2[1], copy_assigned_value); - EXPECT_EQ(buffer2[2], copy_assigned_value); - EXPECT_EQ(buffer2[3], 0); - - buffer1 = 0; - CPPType_TestType.fill_assign_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8}); - EXPECT_EQ(buffer1, copy_assigned_from_value); - EXPECT_EQ(buffer2[0], copy_assigned_value); - EXPECT_EQ(buffer2[1], copy_assigned_value); - EXPECT_EQ(buffer2[2], copy_assigned_value); - EXPECT_EQ(buffer2[3], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer2[5], 0); - EXPECT_EQ(buffer2[6], copy_assigned_value); - EXPECT_EQ(buffer2[7], 0); - EXPECT_EQ(buffer2[8], copy_assigned_value); - EXPECT_EQ(buffer2[9], 0); -} - -TEST(cpp_type, FillUninitialized) -{ - int buffer1 = 0; - int buffer2[10] = {0}; - CPPType_TestType.fill_construct_n((void *)&buffer1, (void *)buffer2, 3); - EXPECT_EQ(buffer1, copy_constructed_from_value); - EXPECT_EQ(buffer2[0], copy_constructed_value); - EXPECT_EQ(buffer2[1], copy_constructed_value); - EXPECT_EQ(buffer2[2], copy_constructed_value); - EXPECT_EQ(buffer2[3], 0); - - buffer1 = 0; - CPPType_TestType.fill_construct_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8}); - EXPECT_EQ(buffer1, copy_constructed_from_value); - EXPECT_EQ(buffer2[0], copy_constructed_value); - EXPECT_EQ(buffer2[1], copy_constructed_value); - EXPECT_EQ(buffer2[2], copy_constructed_value); - EXPECT_EQ(buffer2[3], 0); - EXPECT_EQ(buffer2[4], 0); - EXPECT_EQ(buffer2[5], 0); - EXPECT_EQ(buffer2[6], copy_constructed_value); - EXPECT_EQ(buffer2[7], 0); - EXPECT_EQ(buffer2[8], copy_constructed_value); - EXPECT_EQ(buffer2[9], 0); -} - -TEST(cpp_type, DebugPrint) -{ - int value = 42; - std::stringstream ss; - CPPType::get().print((void *)&value, ss); - std::string text = ss.str(); - EXPECT_EQ(text, "42"); -} - -} // namespace blender::fn::tests diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc index 6417066b47b..ea3c0471411 100644 --- a/source/blender/functions/tests/FN_field_test.cc +++ b/source/blender/functions/tests/FN_field_test.cc @@ -2,7 +2,7 @@ #include "testing/testing.h" -#include "FN_cpp_type.hh" +#include "BLI_cpp_type.hh" #include "FN_field.hh" #include "FN_multi_function_builder.hh" #include "FN_multi_function_test_common.hh" diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 8b469ca38a5..96291be7a96 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -29,7 +29,6 @@ using blender::bke::object_get_evaluated_geometry_set; using blender::bke::OutputAttribute; using blender::bke::OutputAttribute_Typed; using blender::bke::ReadAttributeLookup; -using blender::fn::CPPType; using blender::fn::GArray; using blender::fn::GMutableSpan; using blender::fn::GSpan; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 0b3d9a6a8ad..5b41d46443a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -89,6 +89,7 @@ using blender::Array; using blender::ColorGeometry4f; +using blender::CPPType; using blender::destruct_ptr; using blender::float3; using blender::FunctionRef; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 3733b3f69ad..398f7cb3cf8 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -26,7 +26,6 @@ namespace blender::modifiers::geometry_nodes { -using fn::CPPType; using fn::Field; using fn::GField; using fn::GValueMap; diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 540afc41dba..ce0c027da25 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -32,7 +32,6 @@ using bke::ReadAttributeLookup; using bke::StrongAnonymousAttributeID; using bke::WeakAnonymousAttributeID; using bke::WriteAttributeLookup; -using fn::CPPType; using fn::Field; using fn::FieldContext; using fn::FieldEvaluator; diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index 113a7efb0a5..492c67a236f 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -67,7 +67,7 @@ class GenericValueLog : public ValueLog { class GFieldValueLog : public ValueLog { private: fn::GField field_; - const fn::CPPType &type_; + const CPPType &type_; Vector input_tooltips_; public: @@ -83,7 +83,7 @@ class GFieldValueLog : public ValueLog { return input_tooltips_; } - const fn::CPPType &type() const + const CPPType &type() const { return type_; } diff --git a/source/blender/nodes/geometry/node_geometry_exec.cc b/source/blender/nodes/geometry/node_geometry_exec.cc index 474bfaa214a..58ded7aadd2 100644 --- a/source/blender/nodes/geometry/node_geometry_exec.cc +++ b/source/blender/nodes/geometry/node_geometry_exec.cc @@ -1,10 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "FN_cpp_type_make.hh" +#include "BLI_cpp_type_make.hh" #include "NOD_geometry_exec.hh" -MAKE_CPP_TYPE(GeometrySet, GeometrySet, CPPTypeFlags::Printable); - -namespace blender::nodes { - -} +BLI_CPP_TYPE_MAKE(GeometrySet, GeometrySet, CPPTypeFlags::Printable); diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 5b1b0a21614..5c8f4c52f75 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -15,7 +15,6 @@ namespace blender::nodes::geometry_nodes_eval_log { -using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 948c8376460..0ab446d8b0c 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -10,6 +10,7 @@ #include "DNA_node_types.h" #include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" #include "BLI_listbase.h" #include "BLI_math_vec_types.hh" #include "BLI_string.h" @@ -30,7 +31,6 @@ #include "NOD_node_declaration.hh" #include "NOD_socket.h" -#include "FN_cpp_type_make.hh" #include "FN_field.hh" using namespace blender; @@ -683,11 +683,11 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get>(); + socktype->geometry_nodes_cpp_type = &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -699,11 +699,11 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get>(); + socktype->geometry_nodes_cpp_type = &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -715,11 +715,11 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get>(); + socktype->geometry_nodes_cpp_type = &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -731,11 +731,11 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get>(); + socktype->geometry_nodes_cpp_type = &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -747,12 +747,12 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get>(); + &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -764,11 +764,11 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get>(); + socktype->geometry_nodes_cpp_type = &blender::CPPType::get>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); @@ -778,16 +778,16 @@ static bNodeSocketType *make_socket_type_string() return socktype; } -MAKE_CPP_TYPE(Object, Object *, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(Collection, Collection *, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(Texture, Tex *, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(Image, Image *, CPPTypeFlags::BasicType) -MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(Object, Object *, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(Collection, Collection *, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(Texture, Tex *, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(Image, Image *, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; @@ -799,7 +799,7 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; @@ -811,7 +811,7 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; @@ -823,7 +823,7 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; @@ -835,7 +835,7 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; @@ -847,7 +847,7 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->base_cpp_type = &blender::fn::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; -- cgit v1.2.3