xrpld
Loading...
Searching...
No Matches
io_list.h
1#pragma once
2
3#include <boost/container/flat_map.hpp>
4
5#include <condition_variable>
6#include <cstddef>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <type_traits>
11#include <utility>
12
13namespace xrpl {
14
18class IOList final
19{
20public:
21 class Work
22 {
23 template <class = void>
24 void
26
27 friend class IOList;
28 IOList* ios_ = nullptr;
29
30 public:
31 virtual ~Work()
32 {
33 destroy();
34 }
35
43 IOList&
45 {
46 return *ios_;
47 }
48
49 virtual void
50 close() = 0;
51 };
52
53private:
54 template <class = void>
55 void
56 destroy();
57
60 bool closed_ = false;
62 boost::container::flat_map<Work*, std::weak_ptr<Work>> map_;
63 std::function<void(void)> f_;
64
65public:
66 IOList() = default;
67
78 {
79 destroy();
80 }
81
89 [[nodiscard]] bool
90 closed() const
91 {
92 return closed_;
93 }
94
113 template <class T, class... Args>
115 emplace(Args&&... args);
116
136 template <class Finisher>
137 void
138 close(Finisher&& f);
139
140 void
142 {
143 close([] {});
144 }
145
161 template <class = void>
162 void
163 join();
164};
165
166//------------------------------------------------------------------------------
167
168template <class>
169void
171{
172 if (!ios_)
173 return;
174 std::function<void(void)> f;
175 {
176 std::scoped_lock const lock(ios_->m_);
177 ios_->map_.erase(this);
178 if (--ios_->n_ == 0 && ios_->closed_)
179 {
180 std::swap(f, ios_->f_);
181 ios_->cv_.notify_all();
182 }
183 }
184 if (f)
185 f();
186}
187
188template <class>
189void
191{
192 close();
193 join();
194}
195
196template <class T, class... Args>
198IOList::emplace(Args&&... args)
199{
200 static_assert(std::is_base_of_v<Work, T>, "T must derive from IOList::Work");
201 if (closed_)
202 return nullptr;
203 auto sp = std::make_shared<T>(std::forward<Args>(args)...);
204 decltype(sp) dead;
205
206 std::scoped_lock const lock(m_);
207 if (!closed_)
208 {
209 ++n_;
210 sp->Work::ios_ = this;
211 map_.emplace(sp.get(), sp);
212 }
213 else
214 {
215 std::swap(sp, dead);
216 }
217 return sp;
218}
219
220template <class Finisher>
221void
222IOList::close(Finisher&& f)
223{
225 if (closed_)
226 return;
227 closed_ = true;
228 auto map = std::move(map_);
229 if (!map.empty())
230 {
232 lock.unlock();
233 for (auto const& p : map)
234 {
235 if (auto sp = p.second.lock())
236 sp->close();
237 }
238 }
239 else
240 {
241 lock.unlock();
242 f();
243 }
244}
245
246template <class>
247void
249{
251 cv_.wait(lock, [&] { return closed_ && n_ == 0; });
252}
253
254} // namespace xrpl
virtual ~Work()
Definition io_list.h:31
virtual void close()=0
IOList & ios()
Return the IOList associated with the work.
Definition io_list.h:44
IOList * ios_
Definition io_list.h:28
friend class IOList
Definition io_list.h:27
void close()
Definition io_list.h:141
std::condition_variable cv_
Definition io_list.h:61
std::shared_ptr< T > emplace(Args &&... args)
Create associated work if not closed.
Definition io_list.h:198
void destroy()
Definition io_list.h:190
std::size_t n_
Definition io_list.h:59
std::function< void(void)> f_
Definition io_list.h:63
IOList()=default
~IOList()
Destroy the list.
Definition io_list.h:77
bool closed() const
Return true if the list is closed.
Definition io_list.h:90
std::mutex m_
Definition io_list.h:58
bool closed_
Definition io_list.h:60
void join()
Block until the io_list stops.
Definition io_list.h:248
boost::container::flat_map< Work *, std::weak_ptr< Work > > map_
Definition io_list.h:62
T forward(T... args)
T is_base_of_v
T make_shared(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
T swap(T... args)