Cleanup: simplify subclassing CPPType

`CPPType` can wrap any C++ type so that code can work
with the wrapped type in a generic way. The goal of subclassing
`CPPType` is to provide additional methods for some types.
For example, the `CPPType` for `Array<int>` could have a `.element_type()`
method that returns the `CPPType` for `int`.
This commit is contained in:
Jacques Lucke 2021-08-02 12:43:35 +02:00
parent aa60416361
commit 8edb2222ae
3 changed files with 142 additions and 152 deletions

View File

@ -70,64 +70,73 @@
#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 {
struct CPPTypeMembers {
int64_t size = 0;
int64_t alignment = 0;
uintptr_t alignment_mask = 0;
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 name;
/** Utility class to pass template parameters to constructor of `CPPType`. */
template<typename T, CPPTypeFlags Flags> struct CPPTypeParam {
};
class CPPType : NonCopyable, NonMovable {
private:
CPPTypeMembers m_;
int64_t size_ = 0;
int64_t alignment_ = 0;
uintptr_t alignment_mask_ = 0;
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:
CPPType(CPPTypeMembers members) : m_(std::move(members))
{
BLI_assert(is_power_of_2_i(m_.alignment));
m_.alignment_mask = (uintptr_t)members.alignment - (uintptr_t)1;
m_.has_special_member_functions = (m_.default_construct && m_.copy_construct &&
m_.copy_assign && m_.move_construct && m_.move_assign &&
m_.destruct);
}
template<typename T, CPPTypeFlags Flags> CPPType(CPPTypeParam<T, Flags>, StringRef debug_name);
virtual ~CPPType() = default;
/**
* Two types only compare equal when their pointer is equal. No two instances of CPPType for the
@ -148,7 +157,11 @@ class CPPType : NonCopyable, NonMovable {
* This only works for types that actually implement the template specialization using
* `MAKE_CPP_TYPE`.
*/
template<typename T> static const CPPType &get();
template<typename T> static const CPPType &get()
{
return CPPType::get_impl<std::remove_cv_t<T>>();
}
template<typename T> static const CPPType &get_impl();
/**
* Returns the name of the type for debugging purposes. This name should not be used as
@ -156,7 +169,7 @@ class CPPType : NonCopyable, NonMovable {
*/
StringRefNull name() const
{
return m_.name;
return debug_name_;
}
/**
@ -167,7 +180,7 @@ class CPPType : NonCopyable, NonMovable {
*/
int64_t size() const
{
return m_.size;
return size_;
}
/**
@ -178,7 +191,7 @@ class CPPType : NonCopyable, NonMovable {
*/
int64_t alignment() const
{
return m_.alignment;
return alignment_;
}
/**
@ -190,52 +203,52 @@ class CPPType : NonCopyable, NonMovable {
*/
bool is_trivially_destructible() const
{
return m_.is_trivially_destructible;
return is_trivially_destructible_;
}
bool is_default_constructible() const
{
return m_.default_construct != nullptr;
return default_construct_ != nullptr;
}
bool is_copy_constructible() const
{
return m_.copy_assign != nullptr;
return copy_assign_ != nullptr;
}
bool is_move_constructible() const
{
return m_.move_assign != nullptr;
return move_assign_ != nullptr;
}
bool is_destructible() const
{
return m_.destruct != nullptr;
return destruct_ != nullptr;
}
bool is_copy_assignable() const
{
return m_.copy_assign != nullptr;
return copy_assign_ != nullptr;
}
bool is_move_assignable() const
{
return m_.copy_construct != nullptr;
return copy_construct_ != nullptr;
}
bool is_printable() const
{
return m_.print != nullptr;
return print_ != nullptr;
}
bool is_equality_comparable() const
{
return m_.is_equal != nullptr;
return is_equal_ != nullptr;
}
bool is_hashable() const
{
return m_.hash != nullptr;
return hash_ != nullptr;
}
/**
@ -249,7 +262,7 @@ class CPPType : NonCopyable, NonMovable {
*/
bool has_special_member_functions() const
{
return m_.has_special_member_functions;
return has_special_member_functions_;
}
/**
@ -257,7 +270,7 @@ class CPPType : NonCopyable, NonMovable {
*/
bool pointer_has_valid_alignment(const void *ptr) const
{
return ((uintptr_t)ptr & m_.alignment_mask) == 0;
return ((uintptr_t)ptr & alignment_mask_) == 0;
}
bool pointer_can_point_to_instance(const void *ptr) const
@ -277,7 +290,7 @@ class CPPType : NonCopyable, NonMovable {
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_.default_construct(ptr);
default_construct_(ptr);
}
void default_construct_n(void *ptr, int64_t n) const
@ -289,7 +302,7 @@ class CPPType : NonCopyable, NonMovable {
{
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
m_.default_construct_indices(ptr, mask);
default_construct_indices_(ptr, mask);
}
/**
@ -304,7 +317,7 @@ class CPPType : NonCopyable, NonMovable {
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_.destruct(ptr);
destruct_(ptr);
}
void destruct_n(void *ptr, int64_t n) const
@ -316,7 +329,7 @@ class CPPType : NonCopyable, NonMovable {
{
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
m_.destruct_indices(ptr, mask);
destruct_indices_(ptr, mask);
}
/**
@ -331,7 +344,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.copy_assign(src, dst);
copy_assign_(src, dst);
}
void copy_assign_n(const void *src, void *dst, int64_t n) const
@ -345,7 +358,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.copy_assign_indices(src, dst, mask);
copy_assign_indices_(src, dst, mask);
}
/**
@ -362,7 +375,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.copy_construct(src, dst);
copy_construct_(src, dst);
}
void copy_construct_n(const void *src, void *dst, int64_t n) const
@ -376,7 +389,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.copy_construct_indices(src, dst, mask);
copy_construct_indices_(src, dst, mask);
}
/**
@ -393,7 +406,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.move_assign(src, dst);
move_assign_(src, dst);
}
void move_assign_n(void *src, void *dst, int64_t n) const
@ -407,7 +420,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.move_assign_indices(src, dst, mask);
move_assign_indices_(src, dst, mask);
}
/**
@ -424,7 +437,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.move_construct(src, dst);
move_construct_(src, dst);
}
void move_construct_n(void *src, void *dst, int64_t n) const
@ -438,7 +451,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.move_construct_indices(src, dst, mask);
move_construct_indices_(src, dst, mask);
}
/**
@ -455,7 +468,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.relocate_assign(src, dst);
relocate_assign_(src, dst);
}
void relocate_assign_n(void *src, void *dst, int64_t n) const
@ -469,7 +482,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.relocate_assign_indices(src, dst, mask);
relocate_assign_indices_(src, dst, mask);
}
/**
@ -486,7 +499,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_.relocate_construct(src, dst);
relocate_construct_(src, dst);
}
void relocate_construct_n(void *src, void *dst, int64_t n) const
@ -500,7 +513,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.relocate_construct_indices(src, dst, mask);
relocate_construct_indices_(src, dst, mask);
}
/**
@ -518,7 +531,7 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.fill_assign_indices(value, dst, mask);
fill_assign_indices_(value, dst, mask);
}
/**
@ -536,13 +549,13 @@ class CPPType : NonCopyable, NonMovable {
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
m_.fill_construct_indices(value, dst, mask);
fill_construct_indices_(value, dst, mask);
}
void print(const void *value, std::stringstream &ss) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
m_.print(value, ss);
print_(value, ss);
}
std::string to_string(const void *value) const
@ -566,7 +579,7 @@ class CPPType : NonCopyable, NonMovable {
{
BLI_assert(this->pointer_can_point_to_instance(a));
BLI_assert(this->pointer_can_point_to_instance(b));
return m_.is_equal(a, b);
return is_equal_(a, b);
}
bool is_equal_or_false(const void *a, const void *b) const
@ -580,7 +593,7 @@ class CPPType : NonCopyable, NonMovable {
uint64_t hash(const void *value) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
return m_.hash(value);
return hash_(value);
}
uint64_t hash_or_fallback(const void *value, uint64_t fallback_hash) const
@ -597,7 +610,7 @@ class CPPType : NonCopyable, NonMovable {
*/
const void *default_value() const
{
return m_.default_value;
return default_value_;
}
uint64_t hash() const
@ -605,12 +618,9 @@ class CPPType : NonCopyable, NonMovable {
return get_default_hash(this);
}
/**
* Low level access to the callbacks for this CPPType.
*/
const CPPTypeMembers &members() const
void (*destruct_fn() const)(void *)
{
return m_;
return destruct_;
}
template<typename T> bool is() const

View File

@ -185,100 +185,80 @@ template<typename T> uint64_t hash_cb(const void *value)
} // namespace blender::fn::cpp_type_util
/**
* 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 {
template<typename T, CPPTypeFlags flags>
inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name)
template<typename T, CPPTypeFlags Flags>
CPPType::CPPType(CPPTypeParam<T, Flags> /* unused */, StringRef debug_name)
{
using namespace cpp_type_util;
CPPTypeMembers m;
m.name = name;
m.size = (int64_t)sizeof(T);
m.alignment = (int64_t)alignof(T);
m.is_trivially_destructible = std::is_trivially_destructible_v<T>;
debug_name_ = debug_name;
size_ = (int64_t)sizeof(T);
alignment_ = (int64_t)alignof(T);
is_trivially_destructible_ = std::is_trivially_destructible_v<T>;
if constexpr (std::is_default_constructible_v<T>) {
m.default_construct = default_construct_cb<T>;
m.default_construct_indices = default_construct_indices_cb<T>;
default_construct_ = default_construct_cb<T>;
default_construct_indices_ = default_construct_indices_cb<T>;
static T default_value;
m.default_value = (void *)&default_value;
default_value_ = (void *)&default_value;
}
if constexpr (std::is_destructible_v<T>) {
m.destruct = destruct_cb<T>;
m.destruct_indices = destruct_indices_cb<T>;
destruct_ = destruct_cb<T>;
destruct_indices_ = destruct_indices_cb<T>;
}
if constexpr (std::is_copy_assignable_v<T>) {
m.copy_assign = copy_assign_cb<T>;
m.copy_assign_indices = copy_assign_indices_cb<T>;
copy_assign_ = copy_assign_cb<T>;
copy_assign_indices_ = copy_assign_indices_cb<T>;
}
if constexpr (std::is_copy_constructible_v<T>) {
m.copy_construct = copy_construct_cb<T>;
m.copy_construct_indices = copy_construct_indices_cb<T>;
copy_construct_ = copy_construct_cb<T>;
copy_construct_indices_ = copy_construct_indices_cb<T>;
}
if constexpr (std::is_move_assignable_v<T>) {
m.move_assign = move_assign_cb<T>;
m.move_assign_indices = move_assign_indices_cb<T>;
move_assign_ = move_assign_cb<T>;
move_assign_indices_ = move_assign_indices_cb<T>;
}
if constexpr (std::is_move_constructible_v<T>) {
m.move_construct = move_construct_cb<T>;
m.move_construct_indices = move_construct_indices_cb<T>;
move_construct_ = move_construct_cb<T>;
move_construct_indices_ = move_construct_indices_cb<T>;
}
if constexpr (std::is_destructible_v<T>) {
if constexpr (std::is_move_assignable_v<T>) {
m.relocate_assign = relocate_assign_cb<T>;
m.relocate_assign_indices = relocate_assign_indices_cb<T>;
relocate_assign_ = relocate_assign_cb<T>;
relocate_assign_indices_ = relocate_assign_indices_cb<T>;
}
if constexpr (std::is_move_constructible_v<T>) {
m.relocate_construct = relocate_construct_cb<T>;
m.relocate_construct_indices = relocate_construct_indices_cb<T>;
relocate_construct_ = relocate_construct_cb<T>;
relocate_construct_indices_ = relocate_construct_indices_cb<T>;
}
}
if constexpr (std::is_copy_assignable_v<T>) {
m.fill_assign_indices = fill_assign_indices_cb<T>;
fill_assign_indices_ = fill_assign_indices_cb<T>;
}
if constexpr (std::is_copy_constructible_v<T>) {
m.fill_construct_indices = fill_construct_indices_cb<T>;
fill_construct_indices_ = fill_construct_indices_cb<T>;
}
if constexpr ((bool)(flags & CPPTypeFlags::Hashable)) {
m.hash = hash_cb<T>;
if constexpr ((bool)(Flags & CPPTypeFlags::Hashable)) {
hash_ = hash_cb<T>;
}
if constexpr ((bool)(flags & CPPTypeFlags::Printable)) {
m.print = print_cb<T>;
if constexpr ((bool)(Flags & CPPTypeFlags::Printable)) {
print_ = print_cb<T>;
}
if constexpr ((bool)(flags & CPPTypeFlags::EqualityComparable)) {
m.is_equal = is_equal_cb<T>;
if constexpr ((bool)(Flags & CPPTypeFlags::EqualityComparable)) {
is_equal_ = is_equal_cb<T>;
}
const CPPType *type = new CPPType(std::move(m));
return std::unique_ptr<const CPPType>(type);
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<TYPE_NAME>() \
template<> const blender::fn::CPPType &blender::fn::CPPType::get_impl<TYPE_NAME>() \
{ \
static std::unique_ptr<const CPPType> cpp_type = \
blender::fn::create_cpp_type<TYPE_NAME, FLAGS>(STRINGIFY(IDENTIFIER)); \
return *cpp_type; \
} \
/* Support using `CPPType::get<const T>()`. Otherwise the caller would have to remove const. */ \
template<> const blender::fn::CPPType &blender::fn::CPPType::get<const TYPE_NAME>() \
{ \
return blender::fn::CPPType::get<TYPE_NAME>(); \
static CPPType cpp_type{blender::fn::CPPTypeParam<TYPE_NAME, FLAGS>(), \
STRINGIFY(IDENTIFIER)}; \
return cpp_type; \
}

View File

@ -263,7 +263,7 @@ static Array<MFOutputSocket *> add_constant_folded_sockets(const MultiFunction &
const CPPType &cpp_type = data_type.single_type();
GMutableSpan array = params.computed_array(param_index);
void *buffer = array.data();
scope.add(buffer, array.type().members().destruct, AT);
scope.add(buffer, array.type().destruct_fn(), AT);
constant_fn = &scope.construct<CustomMF_GenericConstant>(AT, cpp_type, buffer);
break;