/* 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 inputs_; const Span outputs_; MutableSpan> input_usages_; Span output_usages_; MutableSpan set_outputs_; public: BasicParams(const LazyFunction &fn, const Span inputs, const Span outputs, MutableSpan> input_usages, Span output_usages, MutableSpan 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; bool try_enable_multi_threading_impl() override; }; namespace detail { /** * Utility to implement #execute_lazy_function_eagerly. */ template inline void execute_lazy_function_eagerly_impl( const LazyFunction &fn, UserData *user_data, std::tuple &inputs, std::tuple &outputs, std::index_sequence /* in_indices */, std::index_sequence /* out_indices */) { constexpr size_t InputsNum = sizeof...(Inputs); constexpr size_t OutputsNum = sizeof...(Outputs); std::array input_pointers; std::array output_pointers; std::array, InputsNum> input_usages; std::array output_usages; std::array set_outputs; ( [&]() { constexpr size_t I = InIndices; /* Use `typedef` instead of `using` to work around a compiler bug. */ typedef Inputs T; const CPPType &type = CPPType::get(); input_pointers[I] = {type, &std::get(inputs)}; }(), ...); ( [&]() { constexpr size_t I = OutIndices; /* Use `typedef` instead of `using` to work around a compiler bug. */ typedef Outputs T; const CPPType &type = CPPType::get(); output_pointers[I] = {type, std::get(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 inline void execute_lazy_function_eagerly(const LazyFunction &fn, UserData *user_data, std::tuple inputs, std::tuple 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(), std::make_index_sequence()); } } // namespace blender::fn::lazy_function