YOrch 1.0.0
Loading...
Searching...
No Matches
plan_exec_slots.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cstddef>
5#include <new>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9
10#include "../assert.hpp"
11#include "../context.hpp"
12#include "../detail/slots/layout.hpp"
13#include "policies.hpp"
14#include "direct_out.hpp"
15
16namespace yorch {
17
18namespace detail {
19
20template <typename Plan, std::size_t I, bool HasLogicalOutput =
21 !std::is_void_v<typename Plan::template output_type<I>>>
23 static constexpr std::size_t value = Plan::no_parent;
24};
25
26template <typename Plan, std::size_t I>
28private:
29 static constexpr auto storage_mode = Plan::template output_storage_mode_for<I>;
30
31public:
32 static constexpr std::size_t value = [] {
33 if constexpr (storage_mode == detail::output_storage_mode::forwarded_prev) {
34 constexpr auto parent = Plan::template parent_index<I>;
35 static_assert(parent != Plan::no_parent,
36 "forward-prev nodes are not allowed at the root");
37 static_assert(!std::is_void_v<typename Plan::template output_type<parent>>,
38 "forward-prev nodes require a direct parent carrying a non-void payload");
40 } else {
41 return I;
42 }
43 }();
44};
45
46template <typename Plan, std::size_t I>
47inline constexpr std::size_t canonical_output_owner_node_v =
49
62template <typename Plan, typename LayoutPolicy>
67
74 destroy_active_slots();
75 }
76
77 template <std::size_t I>
78 using output_type = typename Plan::template output_type<I>;
79
80 template <std::size_t I>
82 Plan::template output_storage_mode_for<I>;
83
84 template <std::size_t I>
85 static constexpr std::size_t slot_index = Plan::template slot_index<I>;
86
90 template <std::size_t I>
92 Plan::template slot_logical_policy_for<I>;
93
97 static constexpr std::size_t physical_slot_count = layout_type::physical_slot_count;
98
102 template <std::size_t I>
103 static constexpr std::size_t physical_slot_index =
104 layout_type::template physical_slot_index<I>;
105
109 template <std::size_t K>
111 layout_type::template physical_slot_policy<K>;
112
116 template <std::size_t I>
117 requires std::is_void_v<output_type<I>>
118 [[nodiscard]] constexpr bool has_value() const noexcept {
119 return false;
120 }
121
125 template <std::size_t I>
126 requires (!std::is_void_v<output_type<I>>) &&
128 [[nodiscard]] constexpr bool has_value() const noexcept {
129 return slot_has_value_impl<I>();
130 }
131
135 template <std::size_t I, typename... Args>
137 constexpr auto emplace(Args&&... args)
138 noexcept(noexcept(slot_view_for<I>().emplace(std::forward<Args>(args)...)))
139 -> output_type<I>& {
140 auto slot = slot_view_for<I>();
141 return slot.emplace(std::forward<Args>(args)...);
142 }
143
147 template <std::size_t I>
150 [[nodiscard]] constexpr auto out() & noexcept -> direct_out<output_type<I>> {
152 }
153
157 template <std::size_t I>
158 requires (!std::is_void_v<output_type<I>>)
159 [[nodiscard]] constexpr auto get() & noexcept -> output_type<I>& {
162 } else {
163 auto slot = slot_view_for<I>();
164 return slot.get();
165 }
166 }
167
171 template <std::size_t I>
172 requires (!std::is_void_v<output_type<I>>)
173 [[nodiscard]] constexpr auto get() const& noexcept -> const output_type<I>& {
176 } else {
177 return *slot_ptr<I>();
178 }
179 }
180
184 template <std::size_t I>
185 constexpr void destroy() noexcept {
186 if constexpr (!std::is_void_v<output_type<I>> &&
188 auto slot = slot_view_for<I>();
189 slot.destroy();
190 }
191 }
192
196 template <std::size_t I>
197 [[nodiscard]] constexpr auto prev_view_for() & {
198 if constexpr (std::is_void_v<output_type<I>>) {
199 return no_prev {};
200 } else {
201 return prev_slot(get<I>());
202 }
203 }
204
208 template <std::size_t I>
209 [[nodiscard]] constexpr auto prev_view_for() const& {
210 if constexpr (std::is_void_v<output_type<I>>) {
211 return no_prev {};
212 } else {
213 return prev_slot(get<I>());
214 }
215 }
216
217private:
218 tuple_type storage {};
219
220 template <std::size_t I>
221 using physical_slot_type =
222 std::tuple_element_t<physical_slot_index<I>, tuple_type>;
223
224 template <std::size_t I>
225 [[nodiscard]] constexpr auto physical_slot() & noexcept -> physical_slot_type<I>& {
226 return std::get<physical_slot_index<I>>(storage);
227 }
228
229 template <std::size_t I>
230 [[nodiscard]] constexpr auto physical_slot() const& noexcept -> const physical_slot_type<I>& {
231 return std::get<physical_slot_index<I>>(storage);
232 }
233
234 template <std::size_t I>
236 [[nodiscard]] constexpr auto slot_view_for() & noexcept -> detail::slot_view<output_type<I>> {
238 }
239
240 template <std::size_t I>
242 [[nodiscard]] constexpr auto slot_ptr() const noexcept -> const output_type<I>* {
244 const auto& slot = physical_slot<I>();
245 const auto* engaged = slot.engaged_ptr();
246 YORCH_ASSERT(engaged != nullptr && *engaged &&
247 "yorch::plan_exec_slots<...>::get() called on an empty slot");
248 }
249
250 return std::launder(reinterpret_cast<const output_type<I>*>(physical_slot<I>().raw_storage()));
251 }
252
253 template <std::size_t I>
254 [[nodiscard]] constexpr bool slot_has_value_impl() const noexcept {
255 if constexpr (std::is_void_v<output_type<I>>) {
256 return false;
257 } else if constexpr (detail::canonical_output_owner_node_v<Plan, I> != I) {
260 const auto& slot = physical_slot<I>();
261 const auto* engaged = slot.engaged_ptr();
262 return engaged != nullptr && *engaged;
263 } else {
264 return true;
265 }
266 }
267
268 template <std::size_t I = 0>
269 constexpr void destroy_active_slots() noexcept {
270 if constexpr (I < Plan::node_count) {
271 if constexpr (detail::payload_node<Plan, I>) {
272 auto& slot = physical_slot<I>();
273 auto* owner_node = slot.owner_node_ptr();
274 if (owner_node != nullptr && *owner_node == I) {
275 auto view = slot_view_for<I>();
276 view.destroy();
277 }
278 }
279
281 }
282 }
283};
284
293template <typename Plan>
297
304 destroy_active_slots();
305 }
306
307 template <std::size_t I>
308 using output_type = typename Plan::template output_type<I>;
309
310 template <std::size_t I>
312 Plan::template output_storage_mode_for<I>;
313
314 template <std::size_t I>
315 static constexpr std::size_t slot_index = Plan::template slot_index<I>;
316
320 template <std::size_t I>
322 Plan::template slot_logical_policy_for<I>;
323
327 static constexpr std::size_t physical_slot_count = layout_type::physical_slot_count;
328
332 template <std::size_t I>
333 static constexpr std::size_t physical_slot_index =
334 layout_type::template physical_slot_index<I>;
335
339 template <std::size_t K>
341 layout_type::template physical_slot_policy<K>;
342
346 template <std::size_t I>
347 requires std::is_void_v<output_type<I>>
348 [[nodiscard]] constexpr bool has_value() const noexcept {
349 return false;
350 }
351
355 template <std::size_t I>
356 requires (!std::is_void_v<output_type<I>>) &&
358 [[nodiscard]] constexpr bool has_value() const noexcept {
359 return slot_has_value_impl<I>();
360 }
361
365 template <std::size_t I, typename... Args>
367 constexpr auto emplace(Args&&... args)
368 noexcept(noexcept(logical_slot<I>().emplace(std::forward<Args>(args)...)))
369 -> output_type<I>& {
370 auto& value = logical_slot<I>().emplace(std::forward<Args>(args)...);
371 live_slots_[I] = true;
372 return value;
373 }
374
378 template <std::size_t I>
381 [[nodiscard]] constexpr auto out() & noexcept -> direct_out<output_type<I>> {
383 }
384
388 template <std::size_t I>
389 requires (!std::is_void_v<output_type<I>>)
390 [[nodiscard]] constexpr auto get() & noexcept -> output_type<I>& {
393 } else {
394 return logical_slot<I>().get();
395 }
396 }
397
401 template <std::size_t I>
402 requires (!std::is_void_v<output_type<I>>)
403 [[nodiscard]] constexpr auto get() const& noexcept -> const output_type<I>& {
406 } else {
407 return logical_slot<I>().get();
408 }
409 }
410
414 template <std::size_t I>
415 constexpr void destroy() noexcept {
416 if constexpr (!std::is_void_v<output_type<I>> &&
419 if (logical_slot<I>().has_value()) {
420 logical_slot<I>().destroy();
421 }
422 } else {
423 if (live_slots_[I]) {
424 logical_slot<I>().destroy();
425 }
426 }
427
428 live_slots_[I] = false;
429 }
430 }
431
435 template <std::size_t I>
436 [[nodiscard]] constexpr auto prev_view_for() & {
437 if constexpr (std::is_void_v<output_type<I>>) {
438 return no_prev {};
439 } else {
440 return prev_slot(get<I>());
441 }
442 }
443
447 template <std::size_t I>
448 [[nodiscard]] constexpr auto prev_view_for() const& {
449 if constexpr (std::is_void_v<output_type<I>>) {
450 return no_prev {};
451 } else {
452 return prev_slot(get<I>());
453 }
454 }
455
456private:
457 tuple_type storage {};
458
459 template <std::size_t I>
460 using logical_slot_type =
461 std::tuple_element_t<physical_slot_index<I>, tuple_type>;
462
463 template <std::size_t I>
464 [[nodiscard]] constexpr auto logical_slot() & noexcept -> logical_slot_type<I>& {
465 return std::get<physical_slot_index<I>>(storage);
466 }
467
468 template <std::size_t I>
469 [[nodiscard]] constexpr auto logical_slot() const& noexcept -> const logical_slot_type<I>& {
470 return std::get<physical_slot_index<I>>(storage);
471 }
472
473 template <std::size_t I>
474 [[nodiscard]] constexpr bool slot_has_value_impl() const noexcept {
475 if constexpr (std::is_void_v<output_type<I>>) {
476 return false;
477 } else if constexpr (detail::canonical_output_owner_node_v<Plan, I> != I) {
480 return logical_slot<I>().has_value();
481 } else {
482 return true;
483 }
484 }
485
486 template <std::size_t I = 0>
487 constexpr void destroy_active_slots() noexcept {
488 if constexpr (I < Plan::node_count) {
489 destroy<I>();
491 }
492 }
493
494 std::array<bool, Plan::node_count> live_slots_ {};
495};
496
497} // namespace detail
498
507template <typename Plan, typename LayoutPolicy = slot_layout_one_to_one_policy>
509struct plan_exec_slots : detail::plan_exec_slots_impl<Plan, LayoutPolicy> {};
510
511template <typename Plan, typename LayoutPolicy = slot_layout_one_to_one_policy>
513
514} // namespace yorch
#define YORCH_ASSERT(condition)
Definition assert.hpp:10
True when node I owns physical storage for its output.
Definition layout.hpp:398
decltype(make_erased_slots_tuple< Layout >(std::make_index_sequence< Layout::physical_slot_count > {})) plan_erased_slots_tuple_t
Erased backend storage tuple for compact/layout-driven plan slots.
Definition layout.hpp:345
output_storage_mode
Describes how a node's logical output is backed at runtime.
Definition policy.hpp:46
decltype(make_typed_slots_tuple< Plan >(std::make_index_sequence< payload_node_count_v< Plan > > {})) plan_typed_slots_tuple_t
Typed backend storage tuple for one-to-one owned payload slots.
Definition layout.hpp:392
slot_physical_policy
Storage-level policy for a physical slot after layout selection.
Definition policy.hpp:32
constexpr std::size_t canonical_output_owner_node_v
slot_logical_policy
Node-local slot semantics inferred from a task's result protocol.
Definition policy.hpp:17
constexpr bool is_adapter_descriptor_v
Definition adapters.hpp:63
constexpr auto value(T &&v) -> value_t< std::remove_cvref_t< T > >
Wraps a value as an owning spec.
Definition specs.hpp:179
constexpr auto prev_slot(T &value) noexcept -> prev_slot_view< T >
Creates a borrowed view over a direct parent payload object.
Definition context.hpp:91
constexpr bool has_value() const noexcept
Reports whether maybe-payload node I currently stores a value.
constexpr void destroy() noexcept
Destroys node I's payload if the node has one.
constexpr auto get() &noexcept -> output_type< I > &
Returns node I's stored payload.
plan_exec_slots_impl & operator=(const plan_exec_slots_impl &)=delete
constexpr auto emplace(Args &&... args) noexcept(noexcept(logical_slot< I >().emplace(std::forward< Args >(args)...))) -> output_type< I > &
Constructs node I's payload in its typed slot.
constexpr auto prev_view_for() &
Returns the from_prev view produced by node I's payload.
constexpr auto out() &noexcept -> direct_out< output_type< I > >
Returns a direct-output sink for maybe-payload node I.
constexpr auto prev_view_for() const &
Returns the const from_prev view produced by node I's payload.
constexpr auto get() const &noexcept -> const output_type< I > &
Returns node I's stored payload from a const slots object.
constexpr bool has_value() const noexcept
Void-output nodes never have a stored payload value.
plan_exec_slots_impl & operator=(plan_exec_slots_impl &&)=delete
Implementation backend for layout-driven erased plan payload storage.
static constexpr std::size_t physical_slot_index
Physical slot index assigned to node I.
constexpr auto get() &noexcept -> output_type< I > &
Returns node I's stored payload.
plan_exec_slots_impl & operator=(const plan_exec_slots_impl &)=delete
static constexpr std::size_t physical_slot_count
Number of physical slots allocated by the selected layout.
detail::plan_erased_slots_tuple_t< layout_type > tuple_type
constexpr auto out() &noexcept -> direct_out< output_type< I > >
Returns a direct-output sink for maybe-payload node I.
constexpr auto prev_view_for() const &
Returns the const from_prev view produced by node I's payload.
constexpr bool has_value() const noexcept
Reports whether maybe-payload node I currently stores a value.
constexpr auto prev_view_for() &
Returns the from_prev view produced by node I's payload.
constexpr void destroy() noexcept
Destroys node I's payload if the node has one.
plan_exec_slots_impl(const plan_exec_slots_impl &)=delete
static constexpr std::size_t slot_index
plan_exec_slots_impl & operator=(plan_exec_slots_impl &&)=delete
plan_exec_slots_impl(plan_exec_slots_impl &&)=delete
constexpr bool has_value() const noexcept
Void-output nodes never have a stored payload value.
constexpr auto emplace(Args &&... args) noexcept(noexcept(slot_view_for< I >().emplace(std::forward< Args >(args)...))) -> output_type< I > &
Constructs node I's payload in its assigned slot.
constexpr auto get() const &noexcept -> const output_type< I > &
Returns node I's stored payload from a const slots object.
typename Plan::template output_type< I > output_type
Output sink passed to direct-output tasks.
Sentinel view indicating that the current execution has no direct parent output.
Definition context.hpp:27
Public per-run plan payload storage entry point.