diff options
author | Jacques Lucke <jacques@blender.org> | 2021-08-18 21:19:12 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-08-18 21:19:12 +0300 |
commit | 41a81474e43623200325fd2d3bbd950c94f5f3ee (patch) | |
tree | 4cb8b14776611dbb78bd61ae24f1c300701fb51e /source/blender | |
parent | aa2822d137e555d30e9eacba9146e32c3663b401 (diff) |
refactor procedure executor
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/functions/intern/multi_function_procedure_executor.cc | 793 |
1 files changed, 614 insertions, 179 deletions
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc index 88c8e1211cf..c76b9b150bd 100644 --- a/source/blender/functions/intern/multi_function_procedure_executor.cc +++ b/source/blender/functions/intern/multi_function_procedure_executor.cc @@ -16,6 +16,8 @@ #include "FN_multi_function_procedure_executor.hh" +#include "BLI_stack.hh" + namespace blender::fn { MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure) @@ -34,344 +36,777 @@ MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &pr using IndicesSplitVectors = std::array<Vector<int64_t>, 2>; -class VariableStore : NonCopyable, NonMovable { - public: - VariableStore() = default; - virtual ~VariableStore() = default; +namespace { +enum class ValueType { + GVArray = 0, + Span = 1, + GVVectorArray = 2, + GVectorArray = 3, + OneSingle = 4, + OneVector = 5, +}; +constexpr int tot_variable_value_types = 6; +} // namespace - virtual void load_as_input(MFParamsBuilder ¶ms) = 0; +struct VariableValue { + ValueType type; - virtual void load_as_mutable(MFParamsBuilder ¶ms, IndexMask full_mask) + VariableValue(ValueType type) : type(type) { - /* Should be overridden by the classes that support it. */ - BLI_assert_unreachable(); - UNUSED_VARS(params, full_mask); } +}; + +/* This variable is the unmodified virtual array from the caller. */ +struct VariableValue_GVArray : public VariableValue { + static inline constexpr ValueType static_type = ValueType::GVArray; + const GVArray &data; - virtual void load_as_output(MFParamsBuilder ¶ms, IndexMask mask, IndexMask full_mask) + VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data) { - /* Should be overridden by the classes that support it. */ - BLI_assert_unreachable(); - UNUSED_VARS(params, mask, full_mask); } +}; + +/* This variable has a different value for every index. Some values may be uninitialized. The span + * may be owned by the caller. */ +struct VariableValue_Span : public VariableValue { + static inline constexpr ValueType static_type = ValueType::Span; + void *data; + bool owned; - virtual void destruct(IndexMask mask) + VariableValue_Span(void *data, bool owned) : VariableValue(static_type), data(data), owned(owned) { - /* Do nothing in the general case. */ - UNUSED_VARS(mask); } +}; + +/* This variable is the unmodified virtual vector array from the caller. */ +struct VariableValue_GVVectorArray : public VariableValue { + static inline constexpr ValueType static_type = ValueType::GVVectorArray; + const GVVectorArray &data; - virtual void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) + VariableValue_GVVectorArray(const GVVectorArray &data) : VariableValue(static_type), data(data) { - /* Should be overridden by the classes that support it. */ - BLI_assert_unreachable(); - UNUSED_VARS(mask, r_indices); } }; -class VariableStore_VirtualSingleFromCaller : public VariableStore { - private: - const GVArray &data_; +/* This variable has a different vector for every index. */ +struct VariableValue_GVectorArray : public VariableValue { + static inline constexpr ValueType static_type = ValueType::GVectorArray; + GVectorArray &data; + bool owned; - public: - VariableStore_VirtualSingleFromCaller(const GVArray &data) : data_(data) + VariableValue_GVectorArray(GVectorArray &data, bool owned) + : VariableValue(static_type), data(data), owned(owned) { } +}; + +/* This variable has the same value for every index. */ +struct VariableValue_OneSingle : public VariableValue { + static inline constexpr ValueType static_type = ValueType::OneSingle; + void *data; + bool is_initialized = false; - void load_as_input(MFParamsBuilder ¶ms) final + VariableValue_OneSingle(void *data) : VariableValue(static_type), data(data) { - params.add_readonly_single_input(data_); } +}; + +/* This variable has the same vector for every index. */ +struct VariableValue_OneVector : public VariableValue { + static inline constexpr ValueType static_type = ValueType::OneVector; + GVectorArray &data; - void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) final + VariableValue_OneVector(GVectorArray &data) : VariableValue(static_type), data(data) { - BLI_assert(data_.type().is<bool>()); - for (const int i : mask) { - bool condition; - data_.get(i, &condition); - r_indices[condition].append(i); - } } }; -class VariableStore_SingleFromCaller : public VariableStore { +static_assert(std::is_trivially_destructible_v<VariableValue_GVArray>); +static_assert(std::is_trivially_destructible_v<VariableValue_Span>); +static_assert(std::is_trivially_destructible_v<VariableValue_GVVectorArray>); +static_assert(std::is_trivially_destructible_v<VariableValue_GVectorArray>); +static_assert(std::is_trivially_destructible_v<VariableValue_OneSingle>); +static_assert(std::is_trivially_destructible_v<VariableValue_OneVector>); + +class VariableState; + +class ValueAllocator : NonCopyable, NonMovable { private: - GMutableSpan data_; + std::array<Stack<VariableValue *>, tot_variable_value_types> values_free_lists_; public: - VariableStore_SingleFromCaller(GMutableSpan data) : data_(data) - { - } + ValueAllocator() = default; - void load_as_input(MFParamsBuilder ¶ms) final + ~ValueAllocator() { - params.add_readonly_single_input(data_); + for (Stack<VariableValue *> &stack : values_free_lists_) { + while (!stack.is_empty()) { + MEM_freeN(stack.pop()); + } + } } - void load_as_mutable(MFParamsBuilder ¶ms, IndexMask UNUSED(full_mask)) final - { - params.add_single_mutable(data_); - } + VariableState *obtain_variable_state(VariableValue &value, int tot_initialized); + + void release_variable_state(VariableState *state); - void load_as_output(MFParamsBuilder ¶ms, - IndexMask UNUSED(mask), - IndexMask UNUSED(full_mask)) final + VariableValue_GVArray *obtain_GVArray(const GVArray &varray) { - params.add_uninitialized_single_output(data_); + return this->obtain<VariableValue_GVArray>(varray); } - void destruct(IndexMask mask) final + VariableValue_GVVectorArray *obtain_GVVectorArray(const GVVectorArray &varray) { - const CPPType &type = data_.type(); - type.destruct_indices(data_.data(), mask); + return this->obtain<VariableValue_GVVectorArray>(varray); } - void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) final + VariableValue_Span *obtain_Span_not_owned(void *buffer) { - Span<bool> conditions = data_.typed<bool>(); - for (const int i : mask) { - r_indices[conditions[i]].append(i); - } + return this->obtain<VariableValue_Span>(buffer, false); } -}; - -class VariableStore_VirtualVectorFromCaller : public VariableStore { - private: - const GVVectorArray &data_; - public: - VariableStore_VirtualVectorFromCaller(const GVVectorArray &data) : data_(data) + VariableValue_Span *obtain_Span(const CPPType &type, int size) { + void *buffer = MEM_mallocN_aligned(type.size() * size, type.alignment(), __func__); + return this->obtain<VariableValue_Span>(buffer, true); } - void load_as_input(MFParamsBuilder ¶ms) final + VariableValue_GVectorArray *obtain_GVectorArray_not_owned(GVectorArray &data) { - params.add_readonly_vector_input(data_); + return this->obtain<VariableValue_GVectorArray>(data, false); } -}; - -class VariableStore_VectorFromCaller : public VariableStore { - private: - GVectorArray &data_; - public: - VariableStore_VectorFromCaller(GVectorArray &data) : data_(data) + VariableValue_GVectorArray *obtain_GVectorArray(const CPPType &type, int size) { + GVectorArray *vector_array = new GVectorArray(type, size); + return this->obtain<VariableValue_GVectorArray>(*vector_array, true); } - void load_as_input(MFParamsBuilder ¶ms) final + VariableValue_OneSingle *obtain_OneSingle(const CPPType &type) { - params.add_readonly_vector_input(data_); + void *buffer = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + return this->obtain<VariableValue_OneSingle>(buffer); } - void load_as_mutable(MFParamsBuilder ¶ms, IndexMask UNUSED(full_mask)) final + VariableValue_OneVector *obtain_OneVector(const CPPType &type) { - params.add_vector_mutable(data_); + GVectorArray *vector_array = new GVectorArray(type, 1); + return this->obtain<VariableValue_OneVector>(*vector_array); } - void load_as_output(MFParamsBuilder ¶ms, - IndexMask UNUSED(mask), - IndexMask UNUSED(full_mask)) final + void release_value(VariableValue *value, const MFDataType &data_type) { - params.add_vector_output(data_); + switch (value->type) { + case ValueType::GVArray: { + break; + } + case ValueType::Span: { + auto *value_typed = static_cast<VariableValue_Span *>(value); + if (value_typed->owned) { + /* Assumes all values in the buffer are uninitialized already. */ + MEM_freeN(value_typed->data); + } + break; + } + case ValueType::GVVectorArray: { + break; + } + case ValueType::GVectorArray: { + auto *value_typed = static_cast<VariableValue_GVectorArray *>(value); + if (value_typed->owned) { + delete &value_typed->data; + } + break; + } + case ValueType::OneSingle: { + auto *value_typed = static_cast<VariableValue_OneSingle *>(value); + if (value_typed->is_initialized) { + const CPPType &type = data_type.single_type(); + type.destruct(value_typed->data); + } + MEM_freeN(value_typed->data); + break; + } + case ValueType::OneVector: { + auto *value_typed = static_cast<VariableValue_OneVector *>(value); + delete &value_typed->data; + break; + } + } + + Stack<VariableValue *> &stack = values_free_lists_[(int)value->type]; + stack.push(value); } - void destruct(IndexMask mask) final + private: + template<typename T, typename... Args> T *obtain(Args &&...args) { - data_.clear(mask); + static_assert(std::is_base_of_v<VariableValue, T>); + Stack<VariableValue *> &stack = values_free_lists_[(int)T::static_type]; + if (stack.is_empty()) { + void *buffer = MEM_mallocN(sizeof(T), __func__); + return new (buffer) T(std::forward<Args>(args)...); + } + return new (stack.pop()) T(std::forward<Args>(args)...); } }; -class VariableStore_SingleOwn : public VariableStore { +class VariableState : NonCopyable, NonMovable { private: - GMutableSpan data_; - int64_t tot_initialized_ = 0; + VariableValue *value_; + int tot_initialized_; public: - VariableStore_SingleOwn(const CPPType &type) : data_(type) + VariableState(VariableValue &value, int tot_initialized) + : value_(&value), tot_initialized_(tot_initialized) { } - ~VariableStore_SingleOwn() final + void destruct_self(ValueAllocator &value_allocator, const MFDataType &data_type) { - void *buffer = data_.data(); - if (buffer != nullptr) { - MEM_freeN(buffer); - } + value_allocator.release_value(value_, data_type); + value_allocator.release_variable_state(this); } - void load_as_input(MFParamsBuilder ¶ms) final + /* True if this contains only one value for all indices, i.e. the value for all indices is + * the same. */ + bool is_one() const { - params.add_readonly_single_input(data_); + switch (value_->type) { + case ValueType::GVArray: + return this->value_as<VariableValue_GVArray>()->data.is_single(); + case ValueType::Span: + return false; + case ValueType::GVVectorArray: + return this->value_as<VariableValue_GVVectorArray>()->data.is_single_vector(); + case ValueType::GVectorArray: + return false; + case ValueType::OneSingle: + return true; + case ValueType::OneVector: + return true; + } + BLI_assert_unreachable(); + return false; } - void load_as_mutable(MFParamsBuilder ¶ms, IndexMask full_mask) final + void add_as_input(MFParamsBuilder ¶ms, IndexMask mask, const MFDataType &data_type) const { - this->ensure_array_buffer(full_mask); - params.add_single_mutable(data_); - } + /* Sanity check to make sure that enough values are initialized. */ + BLI_assert(mask.size() <= tot_initialized_); - void load_as_output(MFParamsBuilder ¶ms, IndexMask mask, IndexMask full_mask) final - { - this->ensure_array_buffer(full_mask); - tot_initialized_ += mask.size(); - params.add_uninitialized_single_output(data_); + switch (value_->type) { + case ValueType::GVArray: { + params.add_readonly_single_input(this->value_as<VariableValue_GVArray>()->data); + break; + } + case ValueType::Span: { + const void *data = this->value_as<VariableValue_Span>()->data; + const GSpan span{data_type.single_type(), data, mask.min_array_size()}; + params.add_readonly_single_input(span); + break; + } + case ValueType::GVVectorArray: { + params.add_readonly_vector_input(this->value_as<VariableValue_GVVectorArray>()->data); + break; + } + case ValueType::GVectorArray: { + params.add_readonly_vector_input(this->value_as<VariableValue_GVectorArray>()->data); + break; + } + case ValueType::OneSingle: { + const auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(value_typed->is_initialized); + const GPointer gpointer{data_type.single_type(), value_typed->data}; + params.add_readonly_single_input(gpointer); + break; + } + case ValueType::OneVector: { + params.add_readonly_vector_input(this->value_as<VariableValue_OneVector>()->data[0]); + break; + } + } } - void destruct(IndexMask mask) final + /* TODO: What happens when the same parameter is passed to the same function more than ones. + * Maybe restrict this so that one variable can only be used either as multiple inputs, one + * mutable or one output. */ + void ensure_is_mutable(IndexMask full_mask, + const MFDataType &data_type, + ValueAllocator &value_allocator) { - const CPPType &type = data_.type(); - type.destruct_indices(data_.data(), mask); - tot_initialized_ -= mask.size(); + if (ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) { + return; + } + + const int array_size = full_mask.min_array_size(); - if (tot_initialized_ == 0) { - void *buffer = data_.data(); - if (buffer != nullptr) { - MEM_freeN(buffer); - data_ = GMutableSpan{data_.type()}; + switch (data_type.category()) { + case MFDataType::Single: { + const CPPType &type = data_type.single_type(); + VariableValue_Span *new_value = value_allocator.obtain_Span(type, array_size); + if (value_->type == ValueType::GVArray) { + /* Fill new buffer with data from virtual array. */ + this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized( + full_mask, new_value->data); + } + else if (value_->type == ValueType::OneSingle) { + auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>(); + if (old_value_typed_->is_initialized) { + /* Fill the buffer with a single value. */ + type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask); + } + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); + value_ = new_value; + break; + } + case MFDataType::Vector: { + const CPPType &type = data_type.vector_base_type(); + VariableValue_GVectorArray *new_value = value_allocator.obtain_GVectorArray(type, + array_size); + if (value_->type == ValueType::GVVectorArray) { + /* Fill new vector array with data from virtual vector array. */ + new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data); + } + else if (value_->type == ValueType::OneVector) { + /* Fill all indices with the same value. */ + const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0]; + new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size}); + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); + value_ = new_value; + break; } } } - void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) final + void add_as_mutable(MFParamsBuilder ¶ms, + IndexMask mask, + IndexMask full_mask, + const MFDataType &data_type, + ValueAllocator &value_allocator) { - Span<bool> conditions = data_.typed<bool>(); - for (const int i : mask) { - r_indices[conditions[i]].append(i); + /* Sanity check to make sure that enough values are initialized. */ + BLI_assert(mask.size() <= tot_initialized_); + + this->ensure_is_mutable(full_mask, data_type, value_allocator); + + switch (value_->type) { + case ValueType::Span: { + void *data = this->value_as<VariableValue_Span>()->data; + const GMutableSpan span{data_type.single_type(), data, mask.min_array_size()}; + params.add_single_mutable(span); + break; + } + case ValueType::GVectorArray: { + params.add_vector_mutable(this->value_as<VariableValue_GVectorArray>()->data); + break; + } + case ValueType::GVArray: + case ValueType::GVVectorArray: + case ValueType::OneSingle: + case ValueType::OneVector: { + BLI_assert_unreachable(); + break; + } } } - private: - void ensure_array_buffer(IndexMask full_mask) - { - const int min_array_size = full_mask.min_array_size(); - if (data_.size() < min_array_size) { - BLI_assert(data_.is_empty()); - const CPPType &type = data_.type(); - void *buffer = MEM_mallocN_aligned(type.size() * min_array_size, type.alignment(), __func__); - data_ = GMutableSpan{type, buffer, min_array_size}; + void add_as_output(MFParamsBuilder ¶ms, + IndexMask mask, + IndexMask full_mask, + const MFDataType &data_type, + ValueAllocator &value_allocator) + { + /* Sanity check to make sure that enough values are not initialized. */ + BLI_assert(mask.size() <= full_mask.size() - tot_initialized_); + this->ensure_is_mutable(full_mask, data_type, value_allocator); + + switch (value_->type) { + case ValueType::Span: { + void *data = this->value_as<VariableValue_Span>()->data; + const GMutableSpan span{data_type.single_type(), data, mask.min_array_size()}; + params.add_uninitialized_single_output(span); + break; + } + case ValueType::GVectorArray: { + params.add_vector_output(this->value_as<VariableValue_GVectorArray>()->data); + break; + } + case ValueType::GVArray: + case ValueType::GVVectorArray: + case ValueType::OneSingle: + case ValueType::OneVector: { + BLI_assert_unreachable(); + break; + } } - } -}; -class VariableStore_VectorOwn : public VariableStore { - private: - const CPPType &type_; - std::unique_ptr<GVectorArray> data_; - int64_t tot_initialized_ = 0; + tot_initialized_ += mask.size(); + } - public: - VariableStore_VectorOwn(const CPPType &type) : type_(type) + void add_as_input__one(MFParamsBuilder ¶ms, const MFDataType &data_type) const { + BLI_assert(this->is_one()); + + switch (value_->type) { + case ValueType::GVArray: { + params.add_readonly_single_input(this->value_as<VariableValue_GVArray>()->data); + break; + } + case ValueType::GVVectorArray: { + params.add_readonly_vector_input(this->value_as<VariableValue_GVVectorArray>()->data); + break; + } + case ValueType::OneSingle: { + const auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(value_typed->is_initialized); + GPointer ptr{data_type.single_type(), value_typed->data}; + params.add_readonly_single_input(ptr); + break; + } + case ValueType::OneVector: { + params.add_readonly_vector_input(this->value_as<VariableValue_OneVector>()->data); + break; + } + case ValueType::Span: + case ValueType::GVectorArray: { + BLI_assert_unreachable(); + break; + } + } } - void load_as_input(MFParamsBuilder ¶ms) final + void ensure_is_mutable__one(const MFDataType &data_type, ValueAllocator &value_allocator) { - params.add_readonly_vector_input(*data_); + BLI_assert(this->is_one()); + if (ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) { + return; + } + + switch (data_type.category()) { + case MFDataType::Single: { + const CPPType &type = data_type.single_type(); + VariableValue_OneSingle *new_value = value_allocator.obtain_OneSingle(type); + if (value_->type == ValueType::GVArray) { + this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized( + new_value->data); + new_value->is_initialized = true; + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); + value_ = new_value; + break; + } + case MFDataType::Vector: { + const CPPType &type = data_type.vector_base_type(); + VariableValue_OneVector *new_value = value_allocator.obtain_OneVector(type); + if (value_->type == ValueType::GVVectorArray) { + const GVVectorArray &old_vector_array = + this->value_as<VariableValue_GVVectorArray>()->data; + new_value->data.extend(IndexRange(1), old_vector_array); + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); + value_ = new_value; + break; + } + } } - void load_as_mutable(MFParamsBuilder ¶ms, IndexMask full_mask) final + void add_as_mutable__one(MFParamsBuilder ¶ms, + const MFDataType &data_type, + ValueAllocator &value_allocator) { - this->ensure_array_buffer(full_mask); - params.add_vector_mutable(*data_); + BLI_assert(this->is_one()); + this->ensure_is_mutable__one(data_type, value_allocator); + + switch (value_->type) { + case ValueType::OneSingle: { + auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(value_typed->is_initialized); + params.add_single_mutable(GMutableSpan{data_type.single_type(), value_typed->data, 1}); + break; + } + case ValueType::OneVector: { + params.add_vector_mutable(this->value_as<VariableValue_OneVector>()->data); + break; + } + case ValueType::GVArray: + case ValueType::Span: + case ValueType::GVVectorArray: + case ValueType::GVectorArray: { + BLI_assert_unreachable(); + break; + } + } } - void load_as_output(MFParamsBuilder ¶ms, IndexMask mask, IndexMask full_mask) final + void add_as_output__one(MFParamsBuilder ¶ms, + IndexMask mask, + const MFDataType &data_type, + ValueAllocator &value_allocator) { - this->ensure_array_buffer(full_mask); + BLI_assert(this->is_one()); + this->ensure_is_mutable__one(data_type, value_allocator); + + switch (value_->type) { + case ValueType::OneSingle: { + auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(!value_typed->is_initialized); + params.add_uninitialized_single_output( + GMutableSpan{data_type.single_type(), value_typed->data, 1}); + break; + } + case ValueType::OneVector: { + auto *value_typed = this->value_as<VariableValue_OneVector>(); + BLI_assert(value_typed->data[0].is_empty()); + params.add_vector_output(this->value_as<VariableValue_OneVector>()->data); + break; + } + case ValueType::GVArray: + case ValueType::Span: + case ValueType::GVVectorArray: + case ValueType::GVectorArray: { + BLI_assert_unreachable(); + break; + } + } + tot_initialized_ += mask.size(); - params.add_vector_output(*data_); } - void destruct(IndexMask mask) final + void destruct(IndexMask mask, + IndexMask full_mask, + const MFDataType &data_type, + ValueAllocator &value_allocator) { - data_->clear(mask); - tot_initialized_ -= mask.size(); + /* Sanity check to make sure that enough indices can be destructed. */ + BLI_assert(tot_initialized_ >= mask.size()); - if (tot_initialized_ == 0) { - data_.reset(); + switch (value_->type) { + case ValueType::GVArray: { + if (mask.size() == full_mask.size()) { + /* All elements are destructed. The elements are owned by the caller, so we don't + * actually destruct them. */ + value_allocator.release_value(value_, data_type); + value_ = value_allocator.obtain_OneSingle(data_type.single_type()); + } + else { + /* Not all elements are destructed. Since we can't work on the original array, we have to + * create a copy first. */ + this->ensure_is_mutable(full_mask, data_type, value_allocator); + BLI_assert(value_->type == ValueType::Span); + const CPPType &type = data_type.single_type(); + type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask); + } + break; + } + case ValueType::Span: { + const CPPType &type = data_type.single_type(); + type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask); + break; + } + case ValueType::GVVectorArray: { + if (mask.size() == full_mask.size()) { + /* All elements are cleared. The elements are owned by the caller, so don't actually + * destruct them. */ + value_allocator.release_value(value_, data_type); + value_ = value_allocator.obtain_OneVector(data_type.vector_base_type()); + } + else { + /* Not all elements are cleared. Since we can't work on the original vector array, we + * have to create a copy first. A possible future optimization is to create the partial + * copy directly. */ + this->ensure_is_mutable(full_mask, data_type, value_allocator); + BLI_assert(value_->type == ValueType::GVectorArray); + this->value_as<VariableValue_GVectorArray>()->data.clear(mask); + } + break; + } + case ValueType::GVectorArray: { + this->value_as<VariableValue_GVectorArray>()->data.clear(mask); + break; + } + case ValueType::OneSingle: { + auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(value_typed->is_initialized); + if (mask.size() == tot_initialized_) { + const CPPType &type = data_type.single_type(); + type.destruct(value_typed->data); + value_typed->is_initialized = false; + } + break; + } + case ValueType::OneVector: { + auto *value_typed = this->value_as<VariableValue_OneVector>(); + if (mask.size() == tot_initialized_) { + value_typed->data.clear({0}); + } + break; + } } + + tot_initialized_ -= mask.size(); } - private: - void ensure_array_buffer(IndexMask full_mask) + void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) { - if (!data_) { - data_ = std::make_unique<GVectorArray>(type_, full_mask.min_array_size()); + BLI_assert(mask.size() <= tot_initialized_); + + switch (value_->type) { + case ValueType::GVArray: { + const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data}; + for (const int i : mask) { + r_indices[varray[i]].append(i); + } + break; + } + case ValueType::Span: { + const Span<bool> span((bool *)this->value_as<VariableValue_Span>()->data, + mask.min_array_size()); + for (const int i : mask) { + r_indices[span[i]].append(i); + } + break; + } + case ValueType::OneSingle: { + auto *value_typed = this->value_as<VariableValue_OneSingle>(); + BLI_assert(value_typed->is_initialized); + const bool condition = *(bool *)value_typed->data; + r_indices[condition].extend(mask); + break; + } + case ValueType::GVVectorArray: + case ValueType::GVectorArray: + case ValueType::OneVector: { + BLI_assert_unreachable(); + break; + } } } + + template<typename T> T *value_as() + { + BLI_assert(value_->type == T::static_type); + return static_cast<T *>(value_); + } + + template<typename T> const T *value_as() const + { + BLI_assert(value_->type == T::static_type); + return static_cast<T *>(value_); + } }; +VariableState *ValueAllocator::obtain_variable_state(VariableValue &value, int tot_initialized) +{ + return new VariableState(value, tot_initialized); +} + +void ValueAllocator::release_variable_state(VariableState *state) +{ + delete state; +} + class VariableStoreContainer { private: - LinearAllocator<> allocator_; - Map<const MFVariable *, destruct_ptr<VariableStore>> stores_; + ValueAllocator value_allocator_; + Map<const MFVariable *, VariableState *> variable_states_; IndexMask full_mask_; public: VariableStoreContainer(const MFProcedureExecutor &fn, const MFProcedure &procedure, - IndexMask mask, + IndexMask full_mask, MFParams ¶ms) - : full_mask_(mask) + : full_mask_(full_mask) { + for (const int param_index : fn.param_indices()) { MFParamType param_type = fn.param_type(param_index); const MFVariable *variable = procedure.params()[param_index].second; + + auto add_state = [&](VariableValue *value, bool input_is_initialized) { + const int tot_initialized = input_is_initialized ? full_mask.size() : 0; + variable_states_.add_new(variable, + value_allocator_.obtain_variable_state(*value, tot_initialized)); + }; + switch (param_type.category()) { case MFParamType::SingleInput: { const GVArray &data = params.readonly_single_input(param_index); - stores_.add_new(variable, - allocator_.construct<VariableStore_VirtualSingleFromCaller>(data)); + add_state(value_allocator_.obtain_GVArray(data), true); break; } case MFParamType::VectorInput: { const GVVectorArray &data = params.readonly_vector_input(param_index); - stores_.add_new(variable, - allocator_.construct<VariableStore_VirtualVectorFromCaller>(data)); + add_state(value_allocator_.obtain_GVVectorArray(data), true); break; } case MFParamType::SingleOutput: { GMutableSpan data = params.uninitialized_single_output(param_index); - stores_.add_new(variable, allocator_.construct<VariableStore_SingleFromCaller>(data)); + add_state(value_allocator_.obtain_Span_not_owned(data.data()), false); break; } case MFParamType::VectorOutput: { GVectorArray &data = params.vector_output(param_index); - stores_.add_new(variable, allocator_.construct<VariableStore_VectorFromCaller>(data)); + add_state(value_allocator_.obtain_GVectorArray_not_owned(data), false); break; } case MFParamType::SingleMutable: { GMutableSpan data = params.single_mutable(param_index); - stores_.add_new(variable, allocator_.construct<VariableStore_SingleFromCaller>(data)); + add_state(value_allocator_.obtain_Span_not_owned(data.data()), true); break; } case MFParamType::VectorMutable: { GVectorArray &data = params.vector_mutable(param_index); - stores_.add_new(variable, allocator_.construct<VariableStore_VectorFromCaller>(data)); + add_state(value_allocator_.obtain_GVectorArray_not_owned(data), true); break; } } } } + ~VariableStoreContainer() + { + for (auto &&item : variable_states_.items()) { + const MFVariable *variable = item.key; + VariableState *state = item.value; + state->destruct_self(value_allocator_, variable->data_type()); + } + } + void load_param(MFParamsBuilder ¶ms, const MFVariable &variable, const MFParamType ¶m_type, const IndexMask &mask) { - VariableStore &store = this->get_store_for_variable(variable); + VariableState &variable_state = this->get_variable_state(variable); switch (param_type.interface_type()) { case MFParamType::Input: { - store.load_as_input(params); + variable_state.add_as_input(params, mask, variable.data_type()); break; } case MFParamType::Mutable: { - store.load_as_mutable(params, full_mask_); + variable_state.add_as_mutable( + params, mask, full_mask_, variable.data_type(), value_allocator_); break; } case MFParamType::Output: { - store.load_as_output(params, mask, full_mask_); + variable_state.add_as_output( + params, mask, full_mask_, variable.data_type(), value_allocator_); break; } } @@ -379,29 +814,27 @@ class VariableStoreContainer { void destruct(const MFVariable &variable, const IndexMask &mask) { - destruct_ptr<VariableStore> *store_ptr = stores_.lookup_ptr(&variable); - if (store_ptr != nullptr) { - store_ptr->get()->destruct(mask); - } + VariableState &variable_state = this->get_variable_state(variable); + variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_); } - VariableStore &get_store_for_variable(const MFVariable &variable) + VariableState &get_variable_state(const MFVariable &variable) { - return *stores_.lookup_or_add_cb( - &variable, [&]() { return this->create_store_for_own_variable(variable); }); + return *variable_states_.lookup_or_add_cb( + &variable, [&]() { return this->create_new_state_for_variable(variable); }); } - destruct_ptr<VariableStore> create_store_for_own_variable(const MFVariable &variable) + VariableState *create_new_state_for_variable(const MFVariable &variable) { MFDataType data_type = variable.data_type(); switch (data_type.category()) { case MFDataType::Single: { const CPPType &type = data_type.single_type(); - return allocator_.construct<VariableStore_SingleOwn>(type); + return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneSingle(type), 0); } case MFDataType::Vector: { const CPPType &type = data_type.vector_base_type(); - return allocator_.construct<VariableStore_VectorOwn>(type); + return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneVector(type), 0); } } BLI_assert_unreachable(); @@ -541,10 +974,10 @@ void MFProcedureExecutor::call(IndexMask mask, MFParams params, MFContext contex const MFBranchInstruction &branch_instruction = static_cast<const MFBranchInstruction &>( instruction); const MFVariable *condition_var = branch_instruction.condition(); - VariableStore &store = variable_stores.get_store_for_variable(*condition_var); + VariableState &variable_state = variable_stores.get_variable_state(*condition_var); IndicesSplitVectors new_indices; - store.indices_split(instr_info.mask(), new_indices); + variable_state.indices_split(instr_info.mask(), new_indices); scheduler.add_owned_indices(branch_instruction.branch_false(), new_indices[false]); scheduler.add_owned_indices(branch_instruction.branch_true(), new_indices[true]); break; @@ -558,6 +991,8 @@ void MFProcedureExecutor::call(IndexMask mask, MFParams params, MFContext contex break; } } + + /* TODO: Make sure outputs are copied into the right place. */ } } |