BLI: improve CPPType system

* Support bidirectional type lookups. E.g. finding the base type of a
  field was supported, but not the other way around. This also removes
  the todo in `get_vector_type`. To achieve this, types have to be
  registered up-front.
* Separate `CPPType` from other "type traits". For example, previously
  `ValueOrFieldCPPType` adds additional behavior on top of `CPPType`.
  Previously, it was a subclass, now it just contains a reference to the
  `CPPType` it corresponds to. This follows the composition-over-inheritance
  idea. This makes it easier to have self-contained "type traits" without
  having to put everything into `CPPType`.

Differential Revision: https://developer.blender.org/D16479
This commit is contained in:
Jacques Lucke 2022-11-12 18:33:31 +01:00
parent a145b96396
commit a6c822733a
27 changed files with 476 additions and 209 deletions

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* Register cpp types and their relations for later use.
*/
void BKE_cpp_types_init(void);
#ifdef __cplusplus
}
#endif

@ -102,6 +102,7 @@ set(SRC
intern/compute_contexts.cc
intern/constraint.c
intern/context.c
intern/cpp_types.cc
intern/crazyspace.cc
intern/cryptomatte.cc
intern/curve.cc
@ -354,6 +355,7 @@ set(SRC
BKE_compute_contexts.hh
BKE_constraint.h
BKE_context.h
BKE_cpp_types.h
BKE_crazyspace.h
BKE_crazyspace.hh
BKE_cryptomatte.h

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types_make.hh"
#include "BKE_cpp_types.h"
#include "BKE_geometry_set.hh"
#include "BKE_instances.hh"
#include "DNA_meshdata_types.h"
#include "FN_init.h"
struct Tex;
struct Image;
struct Material;
BLI_CPP_TYPE_MAKE(GeometrySet, CPPTypeFlags::Printable);
BLI_CPP_TYPE_MAKE(blender::bke::InstanceReference, CPPTypeFlags::None)
BLI_VECTOR_CPP_TYPE_MAKE(GeometrySet);
BLI_CPP_TYPE_MAKE(Object *, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(Collection *, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(Tex *, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(Image *, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(Material *, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(MStringProperty, CPPTypeFlags::None);
void BKE_cpp_types_init()
{
blender::register_cpp_types();
FN_register_cpp_types();
BLI_CPP_TYPE_REGISTER(GeometrySet);
BLI_CPP_TYPE_REGISTER(blender::bke::InstanceReference);
BLI_VECTOR_CPP_TYPE_REGISTER(GeometrySet);
BLI_CPP_TYPE_REGISTER(Object *);
BLI_CPP_TYPE_REGISTER(Collection *);
BLI_CPP_TYPE_REGISTER(Tex *);
BLI_CPP_TYPE_REGISTER(Image *);
BLI_CPP_TYPE_REGISTER(Material *);
BLI_CPP_TYPE_REGISTER(MStringProperty);
}

@ -19,7 +19,6 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
#include "BLI_cpp_type_make.hh"
#include "BLI_endian_switch.h"
#include "BLI_index_range.hh"
#include "BLI_math.h"
@ -5407,5 +5406,3 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer)
{
return LAYERTYPEINFO[layer->type].size;
}
BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None);

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "BLI_cpp_type_make.hh"
#include "BLI_rand.hh"
#include "BLI_task.hh"
@ -9,8 +8,6 @@
#include "BKE_geometry_set.hh"
#include "BKE_instances.hh"
BLI_CPP_TYPE_MAKE(InstanceReference, blender::bke::InstanceReference, CPPTypeFlags::None)
namespace blender::bke {
InstanceReference::InstanceReference(GeometrySet geometry_set)

@ -74,6 +74,7 @@
#include "BLI_index_mask.hh"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_parameter_pack_utils.hh"
#include "BLI_string_ref.hh"
#include "BLI_utility_mixins.hh"
@ -94,10 +95,6 @@ ENUM_OPERATORS(CPPTypeFlags, CPPTypeFlags::EqualityComparable)
namespace blender {
/** Utility class to pass template parameters to constructor of `CPPType`. */
template<typename T, CPPTypeFlags Flags> struct CPPTypeParam {
};
class CPPType : NonCopyable, NonMovable {
private:
int64_t size_ = 0;
@ -148,7 +145,8 @@ class CPPType : NonCopyable, NonMovable {
std::string debug_name_;
public:
template<typename T, CPPTypeFlags Flags> CPPType(CPPTypeParam<T, Flags>, StringRef debug_name);
template<typename T, CPPTypeFlags Flags>
CPPType(TypeTag<T> /*type*/, TypeForValue<CPPTypeFlags, Flags> /*flags*/, StringRef debug_name);
virtual ~CPPType() = default;
/**
@ -173,7 +171,7 @@ class CPPType : NonCopyable, NonMovable {
template<typename T> static const CPPType &get()
{
/* Store the #CPPType locally to avoid making the function call in most cases. */
static const CPPType &type = CPPType::get_impl<std::remove_cv_t<T>>();
static const CPPType &type = CPPType::get_impl<std::decay_t<T>>();
return type;
}
template<typename T> static const CPPType &get_impl();
@ -745,30 +743,26 @@ class CPPType : NonCopyable, NonMovable {
}
}
template<typename T> struct type_tag {
using type = T;
};
private:
template<typename Fn> struct TypeTagExecutor {
const Fn &fn;
template<typename T> void operator()() const
{
fn(type_tag<T>{});
fn(TypeTag<T>{});
}
void operator()() const
{
fn(type_tag<void>{});
fn(TypeTag<void>{});
}
};
public:
/**
* Similar to #to_static_type but is easier to use with a lambda function. The function is
* expected to take a single `auto type_tag` parameter. To extract the static type, use:
* `using T = typename decltype(type_tag)::type;`
* expected to take a single `auto TypeTag` parameter. To extract the static type, use:
* `using T = typename decltype(TypeTag)::type;`
*
* If the current #CPPType is not in #Types, the type tag is `void`.
*/
@ -779,6 +773,11 @@ class CPPType : NonCopyable, NonMovable {
}
};
/**
* Initialize and register basic cpp types.
*/
void register_cpp_types();
} // namespace blender
/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */

@ -206,7 +206,9 @@ template<typename T> uint64_t hash_cb(const void *value)
namespace blender {
template<typename T, CPPTypeFlags Flags>
CPPType::CPPType(CPPTypeParam<T, Flags> /* unused */, StringRef debug_name)
CPPType::CPPType(TypeTag<T> /*type*/,
TypeForValue<CPPTypeFlags, Flags> /*flags*/,
const StringRef debug_name)
{
using namespace cpp_type_util;
@ -278,9 +280,15 @@ CPPType::CPPType(CPPTypeParam<T, Flags> /* unused */, StringRef debug_name)
} // namespace blender
#define BLI_CPP_TYPE_MAKE(IDENTIFIER, TYPE_NAME, FLAGS) \
/** Create a new #CPPType that can be accessed through `CPPType::get<T>()`. */
#define BLI_CPP_TYPE_MAKE(TYPE_NAME, FLAGS) \
template<> const blender::CPPType &blender::CPPType::get_impl<TYPE_NAME>() \
{ \
static CPPType cpp_type{blender::CPPTypeParam<TYPE_NAME, FLAGS>(), STRINGIFY(IDENTIFIER)}; \
return cpp_type; \
static CPPType type{blender::TypeTag<TYPE_NAME>(), \
TypeForValue<CPPTypeFlags, FLAGS>(), \
STRINGIFY(TYPE_NAME)}; \
return type; \
}
/** Register a #CPPType created with #BLI_CPP_TYPE_MAKE. */
#define BLI_CPP_TYPE_REGISTER(TYPE_NAME) blender::CPPType::get<TYPE_NAME>()

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_cpp_type.hh"
#include "BLI_vector.hh"
namespace blender {
/**
* Contains information about how to deal with a #Vector<T> generically.
*/
class VectorCPPType {
public:
/** The #Vector<T> itself. */
const CPPType &self;
/** The type stored in the vector. */
const CPPType &value;
template<typename ValueType> VectorCPPType(TypeTag<ValueType> /*value_type*/);
/**
* Try to find the #VectorCPPType that corresponds to a #CPPType.
*/
static const VectorCPPType *get_from_self(const CPPType &self);
/**
* Try to find the #VectorCPPType that wraps a vector containing the given value type.
* This only works when the vector type has been created with #BLI_VECTOR_CPP_TYPE_MAKE.
*/
static const VectorCPPType *get_from_value(const CPPType &value);
template<typename ValueType> static const VectorCPPType &get()
{
static const VectorCPPType &type = VectorCPPType::get_impl<std::decay_t<ValueType>>();
return type;
}
template<typename ValueType> static const VectorCPPType &get_impl();
private:
void register_self();
};
} // namespace blender

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types.hh"
namespace blender {
template<typename ValueType>
inline VectorCPPType::VectorCPPType(TypeTag<ValueType> /*value_type*/)
: self(CPPType::get<Vector<ValueType>>()), value(CPPType::get<ValueType>())
{
this->register_self();
}
} // namespace blender
/** Create a new #VectorCPPType that can be accessed through `VectorCPPType::get<T>()`. */
#define BLI_VECTOR_CPP_TYPE_MAKE(VALUE_TYPE) \
BLI_CPP_TYPE_MAKE(blender::Vector<VALUE_TYPE>, CPPTypeFlags::None) \
template<> const blender::VectorCPPType &blender::VectorCPPType::get_impl<VALUE_TYPE>() \
{ \
static blender::VectorCPPType type{blender::TypeTag<VALUE_TYPE>{}}; \
return type; \
}
/** Register a #VectorCPPType created with #BLI_VECTOR_CPP_TYPE_MAKE. */
#define BLI_VECTOR_CPP_TYPE_REGISTER(VALUE_TYPE) blender::VectorCPPType::get<VALUE_TYPE>()

@ -23,6 +23,13 @@ template<typename T, T Element> struct TypeForValue {
static constexpr T value = Element;
};
/**
* A struct that allows passing in a type as a function parameter.
*/
template<typename T> struct TypeTag {
using type = T;
};
/**
* A type that encodes a list of values of the same type.
* This is similar to #std::integer_sequence, but a bit more general. It's main purpose it to also

@ -57,7 +57,7 @@ set(SRC
intern/cache_mutex.cc
intern/compute_context.cc
intern/convexhull_2d.c
intern/cpp_type.cc
intern/cpp_types.cc
intern/delaunay_2d.cc
intern/dot_export.cc
intern/dynlib.c
@ -190,6 +190,8 @@ set(SRC
BLI_convexhull_2d.h
BLI_cpp_type.hh
BLI_cpp_type_make.hh
BLI_cpp_types.hh
BLI_cpp_types_make.hh
BLI_delaunay_2d.h
BLI_devirtualize_parameters.hh
BLI_dial_2d.h

@ -1,29 +0,0 @@
/* 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(int8, int8_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int16, int16_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int32, int32_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int64, int64_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint8, uint8_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint16, uint16_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint32, uint32_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint64, uint64_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)
BLI_CPP_TYPE_MAKE(StringVector, blender::Vector<std::string>, CPPTypeFlags::None)

@ -0,0 +1,98 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_color.hh"
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types_make.hh"
#include "BLI_float4x4.hh"
#include "BLI_math_vec_types.hh"
namespace blender {
static auto &get_vector_from_self_map()
{
static Map<const CPPType *, const VectorCPPType *> map;
return map;
}
static auto &get_vector_from_value_map()
{
static Map<const CPPType *, const VectorCPPType *> map;
return map;
}
void VectorCPPType::register_self()
{
get_vector_from_self_map().add_new(&this->self, this);
get_vector_from_value_map().add_new(&this->value, this);
}
const VectorCPPType *VectorCPPType::get_from_self(const CPPType &self)
{
const VectorCPPType *type = get_vector_from_self_map().lookup_default(&self, nullptr);
BLI_assert(type == nullptr || type->self == self);
return type;
}
const VectorCPPType *VectorCPPType::get_from_value(const CPPType &value)
{
const VectorCPPType *type = get_vector_from_value_map().lookup_default(&value, nullptr);
BLI_assert(type == nullptr || type->value == value);
return type;
}
} // namespace blender
BLI_CPP_TYPE_MAKE(bool, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(float, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float2, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float3, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float4x4, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int8_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int16_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int32_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int64_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint8_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint16_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint32_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(uint64_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4f, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4b, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(std::string, CPPTypeFlags::BasicType)
BLI_VECTOR_CPP_TYPE_MAKE(std::string)
namespace blender {
void register_cpp_types()
{
BLI_CPP_TYPE_REGISTER(bool);
BLI_CPP_TYPE_REGISTER(float);
BLI_CPP_TYPE_REGISTER(blender::float2);
BLI_CPP_TYPE_REGISTER(blender::float3);
BLI_CPP_TYPE_REGISTER(blender::float4x4);
BLI_CPP_TYPE_REGISTER(int8_t);
BLI_CPP_TYPE_REGISTER(int16_t);
BLI_CPP_TYPE_REGISTER(int32_t);
BLI_CPP_TYPE_REGISTER(int64_t);
BLI_CPP_TYPE_REGISTER(uint8_t);
BLI_CPP_TYPE_REGISTER(uint16_t);
BLI_CPP_TYPE_REGISTER(uint32_t);
BLI_CPP_TYPE_REGISTER(uint64_t);
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
BLI_CPP_TYPE_REGISTER(std::string);
BLI_VECTOR_CPP_TYPE_REGISTER(std::string);
}
} // namespace blender

@ -76,7 +76,7 @@ struct TestType {
} // namespace blender::tests
BLI_CPP_TYPE_MAKE(TestType, blender::tests::TestType, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::tests::TestType, CPPTypeFlags::BasicType)
namespace blender::tests {

@ -13,6 +13,7 @@ set(INC_SYS
set(SRC
intern/cpp_types.cc
intern/field.cc
intern/field_cpp_type.cc
intern/lazy_function.cc
intern/lazy_function_execute.cc
intern/lazy_function_graph.cc
@ -27,6 +28,8 @@ set(SRC
FN_field.hh
FN_field_cpp_type.hh
FN_field_cpp_type_make.hh
FN_init.h
FN_lazy_function.hh
FN_lazy_function_execute.hh
FN_lazy_function_graph.hh

@ -6,49 +6,15 @@
* \ingroup fn
*/
#include "BLI_cpp_type_make.hh"
#include "FN_field.hh"
namespace blender::fn {
template<typename T> struct FieldCPPTypeParam {
};
class FieldCPPType : public CPPType {
/**
* Contains information about how to deal with a `ValueOrField<T>` generically.
*/
class ValueOrFieldCPPType {
private:
const CPPType &base_type_;
public:
template<typename T>
FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name)
: CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name),
base_type_(CPPType::get<T>())
{
}
const CPPType &base_type() const
{
return base_type_;
}
/* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */
static_assert(sizeof(Field<int>) == sizeof(GField));
static_assert(sizeof(Field<int>) == sizeof(Field<std::string>));
const GField &get_gfield(const void *field) const
{
return *(const GField *)field;
}
void construct_from_gfield(void *r_value, const GField &gfield) const
{
new (r_value) GField(gfield);
}
};
class ValueOrFieldCPPType : public CPPType {
private:
const CPPType &base_type_;
void (*construct_from_value_)(void *dst, const void *value);
void (*construct_from_field_)(void *dst, GField field);
const void *(*get_value_ptr_)(const void *value_or_field);
@ -57,35 +23,12 @@ class ValueOrFieldCPPType : public CPPType {
GField (*as_field_)(const void *value_or_field);
public:
template<typename T>
ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name)
: CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::Printable>(), debug_name),
base_type_(CPPType::get<T>())
{
construct_from_value_ = [](void *dst, const void *value_or_field) {
new (dst) ValueOrField<T>(*(const T *)value_or_field);
};
construct_from_field_ = [](void *dst, GField field) {
new (dst) ValueOrField<T>(Field<T>(std::move(field)));
};
get_value_ptr_ = [](const void *value_or_field) {
return (const void *)&((ValueOrField<T> *)value_or_field)->value;
};
get_field_ptr_ = [](const void *value_or_field) -> const GField * {
return &((ValueOrField<T> *)value_or_field)->field;
};
is_field_ = [](const void *value_or_field) {
return ((ValueOrField<T> *)value_or_field)->is_field();
};
as_field_ = [](const void *value_or_field) -> GField {
return ((ValueOrField<T> *)value_or_field)->as_field();
};
}
/** The #ValueOrField<T> itself. */
const CPPType &self;
/** The type stored in the field. */
const CPPType &value;
const CPPType &base_type() const
{
return base_type_;
}
template<typename ValueType> ValueOrFieldCPPType(TypeTag<ValueType> /*value_type*/);
void construct_from_value(void *dst, const void *value) const
{
@ -122,22 +65,29 @@ class ValueOrFieldCPPType : public CPPType {
{
return as_field_(value_or_field);
}
/**
* Try to find the #ValueOrFieldCPPType that corresponds to a #CPPType.
*/
static const ValueOrFieldCPPType *get_from_self(const CPPType &self);
/**
* Try to find the #ValueOrFieldCPPType that wraps a #ValueOrField containing the given value
* type. This only works when the type has been created with #FN_FIELD_CPP_TYPE_MAKE.
*/
static const ValueOrFieldCPPType *get_from_value(const CPPType &value);
template<typename ValueType> static const ValueOrFieldCPPType &get()
{
static const ValueOrFieldCPPType &type =
ValueOrFieldCPPType::get_impl<std::decay_t<ValueType>>();
return type;
}
private:
template<typename ValueType> static const ValueOrFieldCPPType &get_impl();
void register_self();
};
} // namespace blender::fn
#define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \
template<> const blender::CPPType &blender::CPPType::get_impl<blender::fn::Field<FIELD_TYPE>>() \
{ \
static blender::fn::FieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \
return cpp_type; \
} \
template<> \
const blender::CPPType &blender::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \
{ \
static blender::fn::ValueOrFieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \
STRINGIFY(DEBUG_NAME##OrValue)}; \
return cpp_type; \
}

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "FN_field_cpp_type.hh"
namespace blender::fn {
template<typename ValueType>
inline ValueOrFieldCPPType::ValueOrFieldCPPType(TypeTag<ValueType> /*value_type*/)
: self(CPPType::get<ValueOrField<ValueType>>()), value(CPPType::get<ValueType>())
{
using T = ValueType;
construct_from_value_ = [](void *dst, const void *value_or_field) {
new (dst) ValueOrField<T>(*(const T *)value_or_field);
};
construct_from_field_ = [](void *dst, GField field) {
new (dst) ValueOrField<T>(Field<T>(std::move(field)));
};
get_value_ptr_ = [](const void *value_or_field) {
return (const void *)&((ValueOrField<T> *)value_or_field)->value;
};
get_field_ptr_ = [](const void *value_or_field) -> const GField * {
return &((ValueOrField<T> *)value_or_field)->field;
};
is_field_ = [](const void *value_or_field) {
return ((ValueOrField<T> *)value_or_field)->is_field();
};
as_field_ = [](const void *value_or_field) -> GField {
return ((ValueOrField<T> *)value_or_field)->as_field();
};
this->register_self();
}
} // namespace blender::fn
/**
* Create a new #ValueOrFieldCPPType that can be accessed through `ValueOrFieldCPPType::get<T>()`.
*/
#define FN_FIELD_CPP_TYPE_MAKE(VALUE_TYPE) \
BLI_CPP_TYPE_MAKE(blender::fn::ValueOrField<VALUE_TYPE>, CPPTypeFlags::None) \
template<> \
const blender::fn::ValueOrFieldCPPType & \
blender::fn::ValueOrFieldCPPType::get_impl<VALUE_TYPE>() \
{ \
static blender::fn::ValueOrFieldCPPType type{blender::TypeTag<VALUE_TYPE>{}}; \
return type; \
}
/** Register a #ValueOrFieldCPPType created with #FN_FIELD_CPP_TYPE_MAKE. */
#define FN_FIELD_CPP_TYPE_REGISTER(VALUE_TYPE) blender::fn::ValueOrFieldCPPType::get<VALUE_TYPE>()

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void FN_register_cpp_types(void);
#ifdef __cplusplus
}
#endif

@ -2,20 +2,36 @@
#include "BLI_color.hh"
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types_make.hh"
#include "BLI_float4x4.hh"
#include "BLI_math_vec_types.hh"
#include "FN_field_cpp_type.hh"
#include "FN_field_cpp_type_make.hh"
#include "FN_init.h"
MAKE_FIELD_CPP_TYPE(FloatField, float);
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(ColorGeometry4bField, blender::ColorGeometry4b);
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);
BLI_CPP_TYPE_MAKE(StringValueOrFieldVector,
blender::Vector<blender::fn::ValueOrField<std::string>>,
CPPTypeFlags::None);
FN_FIELD_CPP_TYPE_MAKE(float);
FN_FIELD_CPP_TYPE_MAKE(blender::float2);
FN_FIELD_CPP_TYPE_MAKE(blender::float3);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_MAKE(bool);
FN_FIELD_CPP_TYPE_MAKE(int8_t);
FN_FIELD_CPP_TYPE_MAKE(int32_t);
FN_FIELD_CPP_TYPE_MAKE(std::string);
BLI_VECTOR_CPP_TYPE_MAKE(blender::fn::ValueOrField<std::string>);
void FN_register_cpp_types()
{
FN_FIELD_CPP_TYPE_REGISTER(float);
FN_FIELD_CPP_TYPE_REGISTER(blender::float2);
FN_FIELD_CPP_TYPE_REGISTER(blender::float3);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_REGISTER(bool);
FN_FIELD_CPP_TYPE_REGISTER(int8_t);
FN_FIELD_CPP_TYPE_REGISTER(int32_t);
FN_FIELD_CPP_TYPE_REGISTER(std::string);
BLI_VECTOR_CPP_TYPE_REGISTER(blender::fn::ValueOrField<std::string>);
}

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "FN_field_cpp_type.hh"
namespace blender::fn {
static auto &get_from_self_map()
{
static Map<const CPPType *, const ValueOrFieldCPPType *> map;
return map;
}
static auto &get_from_value_map()
{
static Map<const CPPType *, const ValueOrFieldCPPType *> map;
return map;
}
void ValueOrFieldCPPType::register_self()
{
get_from_value_map().add_new(&this->value, this);
get_from_self_map().add_new(&this->self, this);
}
const ValueOrFieldCPPType *ValueOrFieldCPPType::get_from_self(const CPPType &self)
{
const ValueOrFieldCPPType *type = get_from_self_map().lookup_default(&self, nullptr);
BLI_assert(type == nullptr || type->self == self);
return type;
}
const ValueOrFieldCPPType *ValueOrFieldCPPType::get_from_value(const CPPType &value)
{
const ValueOrFieldCPPType *type = get_from_value_map().lookup_default(&value, nullptr);
BLI_assert(type == nullptr || type->value == value);
return type;
}
} // namespace blender::fn

@ -817,11 +817,10 @@ static void initialize_group_input(NodesModifierData &nmd,
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
attribute_name, *socket_type.base_cpp_type);
GField attribute_field{std::move(attribute_input), 0};
const blender::fn::ValueOrFieldCPPType *cpp_type =
dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(
socket_type.geometry_nodes_cpp_type);
BLI_assert(cpp_type != nullptr);
cpp_type->construct_from_field(r_value, std::move(attribute_field));
const auto *value_or_field_cpp_type = ValueOrFieldCPPType::get_from_self(
*socket_type.geometry_nodes_cpp_type);
BLI_assert(value_or_field_cpp_type != nullptr);
value_or_field_cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
@ -984,9 +983,9 @@ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to
const int index = socket->index();
const GPointer value = output_values[index];
const ValueOrFieldCPPType *cpp_type = dynamic_cast<const ValueOrFieldCPPType *>(value.type());
BLI_assert(cpp_type != nullptr);
const GField field = cpp_type->as_field(value.get());
const auto *value_or_field_type = ValueOrFieldCPPType::get_from_self(*value.type());
BLI_assert(value_or_field_type != nullptr);
const GField field = value_or_field_type->as_field(value.get());
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
&nmd.node_group->outputs, index);

@ -173,7 +173,6 @@ set(SRC
nodes/node_geo_volume_cube.cc
nodes/node_geo_volume_to_mesh.cc
node_geometry_exec.cc
node_geometry_tree.cc
node_geometry_util.cc

@ -1,7 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_cpp_type_make.hh"
#include "NOD_geometry_exec.hh"
BLI_CPP_TYPE_MAKE(GeometrySet, GeometrySet, CPPTypeFlags::Printable);
BLI_CPP_TYPE_MAKE(GeometrySetVector, blender::Vector<GeometrySet>, CPPTypeFlags::None);

@ -16,6 +16,7 @@
#include "NOD_multi_function.hh"
#include "NOD_node_declaration.hh"
#include "BLI_cpp_types.hh"
#include "BLI_lazy_threading.hh"
#include "BLI_map.hh"
@ -53,14 +54,11 @@ static const CPPType *get_socket_cpp_type(const bNodeSocket &socket)
static const CPPType *get_vector_type(const CPPType &type)
{
/* This could be generalized in the future. For now we only support a small set of vectors. */
if (type.is<GeometrySet>()) {
return &CPPType::get<Vector<GeometrySet>>();
const VectorCPPType *vector_type = VectorCPPType::get_from_value(type);
if (vector_type == nullptr) {
return nullptr;
}
if (type.is<ValueOrField<std::string>>()) {
return &CPPType::get<Vector<ValueOrField<std::string>>>();
}
return nullptr;
return &vector_type->self;
}
/**
@ -296,19 +294,17 @@ static void execute_multi_function_on_value_or_field(
for (const int i : input_types.index_range()) {
const ValueOrFieldCPPType &type = *input_types[i];
const CPPType &base_type = type.base_type();
const void *value_or_field = input_values[i];
const void *value = type.get_value_ptr(value_or_field);
params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, value));
params.add_readonly_single_input(GVArray::ForSingleRef(type.value, 1, value));
}
for (const int i : output_types.index_range()) {
const ValueOrFieldCPPType &type = *output_types[i];
const CPPType &base_type = type.base_type();
void *value_or_field = output_values[i];
type.default_construct(value_or_field);
type.self.default_construct(value_or_field);
void *value = type.get_value_ptr(value_or_field);
base_type.destruct(value);
params.add_uninitialized_single_output(GMutableSpan{base_type, value, 1});
type.value.destruct(value);
params.add_uninitialized_single_output(GMutableSpan{type.value, value, 1});
}
fn.call(IndexRange(1), params, context);
}
@ -380,16 +376,14 @@ class LazyFunctionForMutedNode : public LazyFunction {
}
/* Perform a type conversion and then format the value. */
const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
const auto *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&input_type);
const auto *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&output_type);
if (from_field_type != nullptr && to_field_type != nullptr) {
const CPPType &from_base_type = from_field_type->base_type();
const CPPType &to_base_type = to_field_type->base_type();
if (conversions.is_convertible(from_base_type, to_base_type)) {
const auto *from_type = ValueOrFieldCPPType::get_from_self(input_type);
const auto *to_type = ValueOrFieldCPPType::get_from_self(output_type);
if (from_type != nullptr && to_type != nullptr) {
if (conversions.is_convertible(from_type->value, to_type->value)) {
const MultiFunction &multi_fn = *conversions.get_conversion_multi_function(
MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
MFDataType::ForSingle(from_type->value), MFDataType::ForSingle(to_type->value));
execute_multi_function_on_value_or_field(
multi_fn, {}, {from_field_type}, {to_field_type}, {input_value}, {output_value});
multi_fn, {}, {from_type}, {to_type}, {input_value}, {output_value});
}
params.output_set(output_i);
continue;
@ -420,8 +414,8 @@ class LazyFunctionForMultiFunctionConversion : public LazyFunction {
: fn_(fn), from_type_(from), to_type_(to), target_sockets_(std::move(target_sockets))
{
debug_name_ = "Convert";
inputs_.append({"From", from});
outputs_.append({"To", to});
inputs_.append({"From", from.self});
outputs_.append({"To", to.self});
}
void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
@ -458,10 +452,10 @@ class LazyFunctionForMultiFunctionNode : public LazyFunction {
debug_name_ = node.name;
lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_);
for (const lf::Input &fn_input : inputs_) {
input_types_.append(dynamic_cast<const ValueOrFieldCPPType *>(fn_input.type));
input_types_.append(ValueOrFieldCPPType::get_from_self(*fn_input.type));
}
for (const lf::Output &fn_output : outputs_) {
output_types_.append(dynamic_cast<const ValueOrFieldCPPType *>(fn_output.type));
output_types_.append(ValueOrFieldCPPType::get_from_self(*fn_output.type));
}
}
@ -552,8 +546,7 @@ class LazyFunctionForViewerNode : public LazyFunction {
if (use_field_input_) {
const void *value_or_field = params.try_get_input_data_ptr(1);
BLI_assert(value_or_field != nullptr);
const ValueOrFieldCPPType &value_or_field_type = static_cast<const ValueOrFieldCPPType &>(
*inputs_[1].type);
const auto &value_or_field_type = *ValueOrFieldCPPType::get_from_self(*inputs_[1].type);
GField field = value_or_field_type.as_field(value_or_field);
const eAttrDomain domain = eAttrDomain(storage->domain);
const StringRefNull viewer_attribute_name = ".viewer";
@ -1193,14 +1186,13 @@ struct GeometryNodesLazyFunctionGraphBuilder {
if (from_type == to_type) {
return &from_socket;
}
const auto *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&from_type);
const auto *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type);
const auto *from_field_type = ValueOrFieldCPPType::get_from_self(from_type);
const auto *to_field_type = ValueOrFieldCPPType::get_from_self(to_type);
if (from_field_type != nullptr && to_field_type != nullptr) {
const CPPType &from_base_type = from_field_type->base_type();
const CPPType &to_base_type = to_field_type->base_type();
if (conversions_->is_convertible(from_base_type, to_base_type)) {
if (conversions_->is_convertible(from_field_type->value, to_field_type->value)) {
const MultiFunction &multi_fn = *conversions_->get_conversion_multi_function(
MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
MFDataType::ForSingle(from_field_type->value),
MFDataType::ForSingle(to_field_type->value));
auto fn = std::make_unique<LazyFunctionForMultiFunctionConversion>(
multi_fn, *from_field_type, *to_field_type, std::move(target_sockets));
lf::Node &conversion_node = lf_graph_->add_function(*fn);

@ -166,10 +166,9 @@ void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, cons
const GeometrySet &geometry = *value.get<GeometrySet>();
store_logged_value(this->allocator->construct<GeometryInfoLog>(geometry));
}
else if (const auto *value_or_field_type = dynamic_cast<const fn::ValueOrFieldCPPType *>(
&type)) {
else if (const auto *value_or_field_type = fn::ValueOrFieldCPPType::get_from_self(type)) {
const void *value_or_field = value.get();
const CPPType &base_type = value_or_field_type->base_type();
const CPPType &base_type = value_or_field_type->value;
if (value_or_field_type->is_field(value_or_field)) {
const GField *field = value_or_field_type->get_field_ptr(value_or_field);
if (field->node().depends_on_input()) {

@ -10,7 +10,6 @@
#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"
@ -779,12 +778,6 @@ static bNodeSocketType *make_socket_type_string()
return socktype;
}
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);

@ -37,6 +37,7 @@
#include "BKE_cachefile.h"
#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_cpp_types.h"
#include "BKE_global.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
@ -425,6 +426,7 @@ int main(int argc,
BKE_blender_globals_init(); /* blender.c */
BKE_cpp_types_init();
BKE_idtype_init();
BKE_cachefiles_init();
BKE_modifier_init();