60 using function_type = std::function<R(Args...)>;
61 using nothrow_function_type =
62 std::conditional_t<std::is_void_v<R>, function_type, std::function<std::optional<R>(Args...)>>;
64 delegate() : lifetime_observer_{std::make_shared<std::byte>()} {
65 update_readable_buffer();
73 explicit operator bool()
const noexcept {
75 auto func = readable_buffer_;
77 auto func = std::atomic_load_explicit(&readable_buffer_, std::memory_order::acquire);
80 return func &&
static_cast<bool>(*func);
83 decltype(
auto)
operator+=(
const delegate & right) {
84 for (
auto&& [
id, func] : right.listeners_) {
85 add_listener<false>(func);
88 update_readable_buffer();
93 template <std::convertible_to<function_type> Callable>
94 decltype(
auto)
operator+=(Callable && handler) {
95 add_listener<true>(std::forward<Callable>(handler));
100 template <
typename... Equivalents>
101 requires std::is_invocable_r_v<R, function_type, Equivalents...>
102 auto try_invoke(Equivalents&&... args)
const {
104 auto buffer = readable_buffer_;
107 auto buffer = std::atomic_load_explicit(&readable_buffer_, std::memory_order::acquire);
110 if constexpr (std::is_void_v<R>) {
112 for (
auto ptr = buffer.get(); *ptr; ++ptr) {
113 (*ptr)(std::forward<Equivalents>(args)...);
118 return std::optional<R>{};
121 auto ptr = buffer.get();
122 auto tuple = std::forward_as_tuple(std::forward<Equivalents>(args)...);
123 auto handler = [&](
auto inner) -> std::optional<R> {
return std::apply(*inner, std::move(tuple)); };
130 for (; *(ptr + 1); ++ptr) {
131 static_cast<void>(handler(ptr));
139 template <
typename... Equivalents>
140 requires std::is_invocable_r_v<R, function_type, Equivalents...>
141 R operator()(Equivalents&&... args)
const {
142 if constexpr (std::is_void_v<R>) {
143 return try_invoke(std::forward<Equivalents>(args)...);
145 auto result = try_invoke(std::forward<Equivalents>(args)...);
149 U8(
"A delegate with a return value cannot be invoked, within which no subscriber exists.")};
152 return std::move(*result);
156 template <std::convertible_to<function_type> Callable>
157 auto add_listener(Callable&& handler) {
158 auto id = add_listener<true>(std::forward<Callable>(handler));
159 auto lifetime_handler = [
this, id, observer = std::weak_ptr<void>{lifetime_observer_}] {
160 if (
auto lock = observer.lock()) {
165 return std::make_shared<
scope_exit<
decltype(lifetime_handler)>>(std::move(lifetime_handler));
168 function_type to_function()
const {
169 return [
this]<
typename... Equivalents>(
170 Equivalents&&... args) {
return (*
this)(std::forward<Equivalents>(args)...); };
173 nothrow_function_type to_nothrow_function()
const {
174 return [
this]<
typename... Equivalents>(
175 Equivalents&&... args) {
return this->try_invoke(std::forward<Equivalents>(args)...); };
179 template <
bool Update, std::convertible_to<function_type> Callable>
180 auto add_listener(Callable&& handler) {
182 auto counter = ++global_counter_;
184 auto counter = global_counter_.fetch_add(1, std::memory_order::acq_rel) + 1;
187 auto id = listeners_.emplace_back(counter, std::forward<Callable>(handler)).first;
189 if constexpr (Update) {
190 update_readable_buffer();
196 void remove_listener(std::uint64_t
id) {
197 if (
auto iter = std::find_if(listeners_.begin(), listeners_.end(),
198 [&](
const std::pair<std::uint64_t, function_type>& inner) { return inner.first == id; });
199 iter != listeners_.end()) {
200 listeners_.erase(iter);
201 update_readable_buffer();
205 void update_readable_buffer() {
209#if __cpp_lib_smart_ptr_for_overwrite >= 202002L
210 auto buffer = std::static_pointer_cast<function_type>(
211 std::make_shared_for_overwrite<function_type[]>(listeners_.size() + 1));
213 std::shared_ptr<function_type> buffer{
214 new function_type[listeners_.size() + 1], std::default_delete<function_type[]> {}};
216 std::transform(listeners_.begin(), listeners_.end(), buffer.get(),
217 [](
const std::pair<std::uint64_t, function_type>& inner) { return inner.second; });
220 readable_buffer_ = std::move(buffer);
222 std::atomic_store_explicit(&readable_buffer_, std::move(buffer), std::memory_order::release);
226 std::vector<std::pair<std::uint64_t, function_type>> listeners_;
229 std::shared_ptr<function_type> readable_buffer_;
230#elif __cpp_lib_atomic_shared_ptr >= 201711L
231 std::atomic<std::shared_ptr<function_type>> readable_buffer_;
233 std::shared_ptr<function_type> readable_buffer_;
236 std::shared_ptr<void> lifetime_observer_;
239 inline static std::uint64_t global_counter_;
241 inline static std::atomic_uint64_t global_counter_;