diff options
Diffstat (limited to 'source/blender/functions/FN_lazy_function_execute.hh')
-rw-r--r-- | source/blender/functions/FN_lazy_function_execute.hh | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/source/blender/functions/FN_lazy_function_execute.hh b/source/blender/functions/FN_lazy_function_execute.hh new file mode 100644 index 00000000000..5a80985cdc0 --- /dev/null +++ b/source/blender/functions/FN_lazy_function_execute.hh @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup fn + * + * This file contains common utilities for actually executing a lazy-function. + */ + +#include "BLI_parameter_pack_utils.hh" + +#include "FN_lazy_function.hh" + +namespace blender::fn::lazy_function { + +/** + * Most basic implementation of #Params. It does not actually implement any logic for how to + * retrieve inputs or set outputs. Instead, code using #BasicParams has to implement that. + */ +class BasicParams : public Params { + private: + const Span<GMutablePointer> inputs_; + const Span<GMutablePointer> outputs_; + MutableSpan<std::optional<ValueUsage>> input_usages_; + Span<ValueUsage> output_usages_; + MutableSpan<bool> set_outputs_; + + public: + BasicParams(const LazyFunction &fn, + const Span<GMutablePointer> inputs, + const Span<GMutablePointer> outputs, + MutableSpan<std::optional<ValueUsage>> input_usages, + Span<ValueUsage> output_usages, + MutableSpan<bool> set_outputs); + + void *try_get_input_data_ptr_impl(const int index) const override; + void *try_get_input_data_ptr_or_request_impl(const int index) override; + void *get_output_data_ptr_impl(const int index) override; + void output_set_impl(const int index) override; + bool output_was_set_impl(const int index) const override; + ValueUsage get_output_usage_impl(const int index) const override; + void set_input_unused_impl(const int index) override; +}; + +namespace detail { + +/** + * Utility to implement #execute_lazy_function_eagerly. + */ +template<typename... Inputs, typename... Outputs, size_t... InIndices, size_t... OutIndices> +inline void execute_lazy_function_eagerly_impl( + const LazyFunction &fn, + UserData *user_data, + std::tuple<Inputs...> &inputs, + std::tuple<Outputs *...> &outputs, + std::index_sequence<InIndices...> /* in_indices */, + std::index_sequence<OutIndices...> /* out_indices */) +{ + constexpr size_t InputsNum = sizeof...(Inputs); + constexpr size_t OutputsNum = sizeof...(Outputs); + std::array<GMutablePointer, InputsNum> input_pointers; + std::array<GMutablePointer, OutputsNum> output_pointers; + std::array<std::optional<ValueUsage>, InputsNum> input_usages; + std::array<ValueUsage, OutputsNum> output_usages; + std::array<bool, OutputsNum> set_outputs; + ( + [&]() { + constexpr size_t I = InIndices; + typedef Inputs T; + const CPPType &type = CPPType::get<T>(); + input_pointers[I] = {type, &std::get<I>(inputs)}; + }(), + ...); + ( + [&]() { + constexpr size_t I = OutIndices; + typedef Outputs T; + const CPPType &type = CPPType::get<T>(); + output_pointers[I] = {type, std::get<I>(outputs)}; + }(), + ...); + output_usages.fill(ValueUsage::Used); + set_outputs.fill(false); + LinearAllocator<> allocator; + Context context; + context.user_data = user_data; + context.storage = fn.init_storage(allocator); + BasicParams params{ + fn, input_pointers, output_pointers, input_usages, output_usages, set_outputs}; + fn.execute(params, context); + fn.destruct_storage(context.storage); +} + +} // namespace detail + +/** + * In some cases (mainly for tests), the set of inputs and outputs for a lazy-function is known at + * compile time and one just wants to compute the outputs based on the inputs, without any + * laziness. + * + * This function does exactly that. It takes all inputs in a tuple and writes the outputs to points + * provided in a second tuple. Since all inputs have to be provided, the lazy-function has to + * compute all outputs. + */ +template<typename... Inputs, typename... Outputs> +inline void execute_lazy_function_eagerly(const LazyFunction &fn, + UserData *user_data, + std::tuple<Inputs...> inputs, + std::tuple<Outputs *...> outputs) +{ + BLI_assert(fn.inputs().size() == sizeof...(Inputs)); + BLI_assert(fn.outputs().size() == sizeof...(Outputs)); + detail::execute_lazy_function_eagerly_impl(fn, + user_data, + inputs, + outputs, + std::make_index_sequence<sizeof...(Inputs)>(), + std::make_index_sequence<sizeof...(Outputs)>()); +} + +} // namespace blender::fn::lazy_function |