diff options
author | Jacques Lucke <jacques@blender.org> | 2022-03-18 12:57:45 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-03-18 12:57:45 +0300 |
commit | 2252bc6a5527cd7360d1ccfe7a2d1bc640a8dfa6 (patch) | |
tree | bb6f8921b9977dc2c387b750a29aa6ded06ec5f9 /source/blender/functions/FN_cpp_type.hh | |
parent | 7509a741166c97f5f87ed9e580eef6f99eb1e62a (diff) |
BLI: move CPPType to blenlib
For more detail about `CPPType`, see `BLI_cpp_type.hh` and D14367.
Differential Revision: https://developer.blender.org/D14367
Diffstat (limited to 'source/blender/functions/FN_cpp_type.hh')
-rw-r--r-- | source/blender/functions/FN_cpp_type.hh | 635 |
1 files changed, 0 insertions, 635 deletions
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<typename T, CPPTypeFlags Flags> 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<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 - * 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<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 - * 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<T>; - */ - 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<T>; - */ - 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<typename T> bool is() const - { - return this == &CPPType::get<std::decay_t<T>>(); - } -}; - -} // 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(); |