ReactivePlusPlus
ReactiveX implementation for C++20
Loading...
Searching...
No Matches
disposable_wrapper.hpp
1// ReactivePlusPlus library
2//
3// Copyright Aleksey Loginov 2023 - present.
4// Distributed under the Boost Software License, Version 1.0.
5// (See accompanying file LICENSE_1_0.txt or copy at
6// https://www.boost.org/LICENSE_1_0.txt)
7//
8// Project home: https://github.com/victimsnino/ReactivePlusPlus
9//
10
11#pragma once
12
13#include <rpp/disposables/fwd.hpp>
14
15#include <rpp/defs.hpp>
16#include <rpp/disposables/interface_disposable.hpp>
17#include <rpp/utils/utils.hpp>
18
19#include <memory>
20#include <variant>
21
22namespace rpp::details
23{
24 template<rpp::constraint::decayed_type TDisposable>
25 class enable_wrapper_from_this;
26
27 template<rpp::constraint::decayed_type TDisposable>
28 class auto_dispose_wrapper final
29 {
30 public:
31 static_assert(std::derived_from<TDisposable, interface_disposable>);
32
33 template<typename... TArgs>
34 requires (std::constructible_from<TDisposable, TArgs && ...> && !rpp::constraint::variadic_decayed_same_as<auto_dispose_wrapper, TArgs...>)
35 explicit auto_dispose_wrapper(TArgs&&... args)
36 : m_data{std::forward<TArgs>(args)...}
37 {
38 }
39
40 auto_dispose_wrapper(const auto_dispose_wrapper&) = delete;
41 auto_dispose_wrapper(auto_dispose_wrapper&&) noexcept = delete;
42
43 ~auto_dispose_wrapper() noexcept
44 {
45 static_cast<interface_disposable&>(m_data).dispose_impl(rpp::interface_disposable::Mode::Destroying);
46 }
47
48 TDisposable* get() { return &m_data; }
49
50 private:
51 RPP_NO_UNIQUE_ADDRESS TDisposable m_data;
52 };
53
55 {
56 public:
57 bool operator==(const disposable_wrapper_base& other) const
58 {
59 return get().first == other.get().first;
60 }
61
62 bool is_disposed() const noexcept
63 {
64 if (const auto locked = get().first)
65 return locked->is_disposed();
66 return true;
67 }
68
69 void dispose() const noexcept
70 {
71 if (const auto locked = get().first)
72 locked->dispose();
73 }
74
75 protected:
76 explicit disposable_wrapper_base(std::shared_ptr<interface_disposable>&& disposable)
77 : m_disposable{std::move(disposable)}
78 {
79 }
80
81 explicit disposable_wrapper_base(std::weak_ptr<interface_disposable>&& disposable)
82 : m_disposable{std::move(disposable)}
83 {
84 }
85
86 disposable_wrapper_base() = default;
87
88 std::pair<std::shared_ptr<interface_disposable>, bool> get() const noexcept
89 {
90 if (const auto ptr_ptr = std::get_if<std::shared_ptr<interface_disposable>>(&m_disposable))
91 return {*ptr_ptr, true};
92
93 if (const auto ptr_ptr = std::get_if<std::weak_ptr<interface_disposable>>(&m_disposable))
94 return {ptr_ptr->lock(), false};
95
96 return {nullptr, true};
97 }
98
99 private:
100 std::variant<std::monostate, std::shared_ptr<interface_disposable>, std::weak_ptr<interface_disposable>> m_disposable;
101 };
102
103} // namespace rpp::details
104
105namespace rpp
106{
140 template<rpp::constraint::decayed_type TDisposable>
142 {
143 using TDefaultMake = std::conditional_t<std::same_as<TDisposable, interface_composite_disposable>, composite_disposable, TDisposable>;
144
145 public:
146 template<constraint::decayed_type TTarget>
147 friend class disposable_wrapper_impl;
148
149 template<rpp::constraint::decayed_type TTarget>
151
152 bool operator==(const disposable_wrapper_impl&) const = default;
153
162 template<std::derived_from<TDisposable> TTarget = TDefaultMake, typename... TArgs>
163 requires (std::constructible_from<TTarget, TArgs && ...>)
164 [[nodiscard]] static disposable_wrapper_impl make(TArgs&&... args)
165 {
166 const auto ptr = std::make_shared<details::auto_dispose_wrapper<TTarget>>(std::forward<TArgs>(args)...);
167 auto base_ptr = std::shared_ptr<TDisposable>{ptr, static_cast<TDisposable*>(ptr->get())};
169 {
170 base_ptr->set_weak_self(std::weak_ptr<interface_disposable>(base_ptr));
171 }
172 return disposable_wrapper_impl{std::static_pointer_cast<interface_disposable>(std::move(base_ptr))};
173 }
174
178 [[nodiscard]] static disposable_wrapper_impl empty()
179 {
181 }
182
183 template<rpp::constraint::is_nothrow_invocable Fn>
184 disposable_wrapper add(Fn&& invocable)
185 requires std::derived_from<TDisposable, interface_composite_disposable>
186 {
187 auto d = make_callback_disposable(std::forward<Fn>(invocable));
188 add(d);
189 return d;
190 }
191
192 void add(disposable_wrapper other) const
193 requires std::derived_from<TDisposable, interface_composite_disposable>
194 {
195 if (const auto locked = lock())
196 locked->add(std::move(other));
197 else
198 other.dispose();
199 }
200
201 void remove(const disposable_wrapper& other) const
202 requires std::derived_from<TDisposable, interface_composite_disposable>
203 {
204 if (const auto locked = lock())
205 locked->remove(other);
206 }
207
208 void clear() const
209 requires std::derived_from<TDisposable, interface_composite_disposable>
210 {
211 if (const auto locked = lock())
212 locked->clear();
213 }
214
215 [[nodiscard]] std::shared_ptr<TDisposable> lock() const noexcept
216 {
217 return std::static_pointer_cast<TDisposable>(get().first);
218 }
219
220 [[nodiscard]] disposable_wrapper_impl as_weak() const
221 {
222 auto [locked, is_shared] = get();
223 if (is_shared)
224 return disposable_wrapper_impl{std::weak_ptr<interface_disposable>{locked}};
225 return *this;
226 }
227
228 template<constraint::decayed_type TTarget>
230 operator disposable_wrapper_impl<TTarget>() const
231 {
232 auto [locked, is_shared] = get();
233 if (!locked)
235
236 auto res = disposable_wrapper_impl<TTarget>{std::move(locked)};
237 if (is_shared)
238 return res;
239
240 return res.as_weak();
241 }
242
243 private:
244 using details::disposable_wrapper_base::disposable_wrapper_base;
245 };
246} // namespace rpp
247
248namespace rpp::details
249{
250 template<rpp::constraint::decayed_type TStrategy>
252 {
253 public:
254 template<rpp::constraint::decayed_type TSource>
255 friend class rpp::disposable_wrapper_impl;
256
257 protected:
258 enable_wrapper_from_this() = default;
259
260 void set_weak_self(std::weak_ptr<interface_disposable> weak)
261 {
262 m_weak = std::move(weak);
263 }
264
265 public:
266 disposable_wrapper_impl<TStrategy> wrapper_from_this() const
267 {
268 return disposable_wrapper_impl<TStrategy>(std::static_pointer_cast<interface_disposable>(m_weak.lock()));
269 }
270
271 private:
272 std::weak_ptr<interface_disposable> m_weak{};
273 };
274} // namespace rpp::details
Disposable which can keep some other sub-disposables. When this root disposable is disposed,...
Definition composite_disposable.hpp:175
Definition disposable_wrapper.hpp:55
Definition disposable_wrapper.hpp:252
Main RPP wrapper over disposables.
Definition fwd.hpp:27
static disposable_wrapper_impl make(TArgs &&... args)
Main way to create disposable_wrapper. Passed TTarget type can be any type derived from TDisposable.
Definition disposable_wrapper.hpp:164
static disposable_wrapper_impl empty()
Creates disposable_wrapper which behaves like disposed disposable.
Definition disposable_wrapper.hpp:178
Definition constraints.hpp:31
Definition utils.hpp:48
disposable_wrapper_impl< interface_disposable > disposable_wrapper
Wrapper to keep "simple" disposable. Specialization of rpp::disposable_wrapper_impl.
Definition fwd.hpp:34