YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
shared_event.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#if YACLIB_CORO != 0
7# include <yaclib/coro/coro.hpp>
8#endif
9
10#include <array>
11#include <vector>
12
13namespace yaclib::detail {
14
15// Used to wait on multiple shared futures
16// because shared cores enqueue callbacks intrusively
17// so we need many inline cores (many .next pointers)
18// This callback just dispatches to the Event's CallCallback
19template <typename Event>
21 // Default ctor needed for use inside std::array
25
26 [[nodiscard]] InlineCore* Here(InlineCore& caller) noexcept {
27 return event->GetCall().Here(caller);
28 }
29
30 // TODO(ocelaiwo): For now shared futures never do symmetric transfer
31 // It is possile to do so if the last callback is to destroy the shared core
32#if YACLIB_SYMMETRIC_TRANSFER != 0
33 [[nodiscard]] yaclib_std::coroutine_handle<> Next(InlineCore& caller) noexcept final { // LCOV_EXCL_LINE
34 return event->GetCall().Next(caller); // LCOV_EXCL_LINE
35 } // LCOV_EXCL_LINE
36#endif
37
39};
40
41template <typename Event, size_t SharedCount>
42struct StaticSharedEvent : public Event {
43 static constexpr bool kShared = true;
44
46 callbacks.fill(this);
47 }
48
49 std::array<EventHelperCallback<Event>, SharedCount> callbacks;
50};
51
52template <typename Event>
53struct DynamicSharedEvent : public Event {
54 static constexpr bool kShared = true;
55
58
59 std::vector<EventHelperCallback<Event>> callbacks;
60};
61
62template <typename Event, typename... Handles>
64 static_assert(sizeof...(handles) >= 2, "Number of futures must be at least two");
65 const auto wait_count = [&] {
66 if constexpr (!Event::kShared) {
67 auto setter = [&](auto handle) {
68 return handle.SetCallback(event);
69 };
70 return (... + static_cast<std::size_t>(setter(handles)));
71 } else {
72 auto setter = [&, callback_count = std::size_t{}](auto handle) mutable {
73 if constexpr (std::is_same_v<decltype(handle), UniqueHandle>) {
74 return handle.SetCallback(event);
75 } else {
76 return handle.SetCallback(event.callbacks[callback_count++]);
77 }
78 };
79 return (... + static_cast<std::size_t>(setter(handles)));
80 }
81 }();
82
83 event.count.fetch_sub(sizeof...(handles) - wait_count, std::memory_order_relaxed);
84}
85
86template <typename Event, typename It>
87void SetCallbacksDynamic(Event& event, It it, std::size_t count) {
88 std::size_t wait_count = 0;
89 for (std::size_t i = 0; i != count; ++i) {
90 YACLIB_ASSERT(it->Valid());
91 if constexpr (std::is_same_v<decltype(it->GetHandle()), UniqueHandle>) {
92 wait_count += static_cast<std::size_t>(it->GetHandle().SetCallback(event));
93 } else {
94 wait_count += static_cast<std::size_t>(it->GetHandle().SetCallback(event.callbacks[i]));
95 }
96 ++it;
97 }
98 event.count.fetch_sub(count - wait_count, std::memory_order_relaxed);
99}
100
101} // namespace yaclib::detail
virtual InlineCore * Here(InlineCore &caller) noexcept=0
#define YACLIB_ASSERT(cond)
Definition log.hpp:85
void SetCallbacksStatic(Event &event, Handles... handles)
void SetCallbacksDynamic(Event &event, It it, std::size_t count)
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
std::vector< EventHelperCallback< Event > > callbacks
DynamicSharedEvent(size_t total_count)
InlineCore * Here(InlineCore &caller) noexcept
std::array< EventHelperCallback< Event >, SharedCount > callbacks
StaticSharedEvent(size_t total_count)