A bunch of random code samples
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

533 lignes
13 KiB

il y a 1 mois
  1. #pragma once
  2. #include <mutex>
  3. #include <algorithm>
  4. #include <functional>
  5. #include <memory>
  6. #include <thread>
  7. #include <optional>
  8. namespace _details {
  9. template<typename T>
  10. using optional = std::optional<T>; //< Configuration constant on which optional to use to implement the rest of this file
  11. auto nullopt = std::nullopt; //< Configuration constant on which optional to use to implement the rest of this file
  12. struct awaiter {
  13. void operator()(int duration) {
  14. std::this_thread::sleep_for(std::chrono::milliseconds(duration));
  15. }
  16. };
  17. struct defer_impl {
  18. std::function<void(void)> fn;
  19. ~defer_impl() {
  20. fn();
  21. }
  22. };
  23. #ifdef defer
  24. #warning "A defer macro is already defined and will be undefined after this file"
  25. #undef defer
  26. #endif
  27. #define defer(name, h) _details::defer_impl _defer_slice ## name {[&](){(h);}};
  28. struct _do_not_use_t {
  29. };
  30. constexpr _do_not_use_t do_not_use{};
  31. }
  32. namespace container {
  33. template<typename T>
  34. class circular_buffer_iterator {
  35. struct M {
  36. T *buffer;
  37. size_t capacity;
  38. size_t index;
  39. };
  40. M m;
  41. explicit circular_buffer_iterator(M members)
  42. : m{members} {}
  43. public:
  44. using difference_type = size_t;
  45. using value_type = T;
  46. using pointer = T *;
  47. using reference = T &;
  48. using iterator_category = std::bidirectional_iterator_tag;
  49. circular_buffer_iterator(T *buffer, size_t capacity, size_t index)
  50. : m{M{
  51. .buffer = buffer,
  52. .capacity = capacity,
  53. .index = index
  54. }} {}
  55. circular_buffer_iterator &operator++() {
  56. m.index = (m.index + 1) bitand (m.capacity - 1);
  57. return *this;
  58. }
  59. circular_buffer_iterator operator++(int) {
  60. M oth = m;
  61. m.index = (m.index + 1) bitand (m.capacity - 1);
  62. return circular_buffer_iterator{oth};
  63. }
  64. circular_buffer_iterator &operator--() {
  65. m.index = (m.index - 1) bitand (m.capacity - 1);
  66. return *this;
  67. }
  68. circular_buffer_iterator operator--(int) {
  69. M oth = m;
  70. m.index = (m.index - 1) bitand (m.capacity - 1);
  71. return circular_buffer_iterator{oth};
  72. }
  73. T &operator*() {
  74. return m.buffer[m.index];
  75. }
  76. bool operator==(const circular_buffer_iterator &oth) {
  77. return m == oth.m;
  78. }
  79. bool operator!=(const circular_buffer_iterator &oth) {
  80. return m.buffer != oth.m.buffer or m.index != oth.m.index or m.capacity != oth.m.capacity;
  81. }
  82. };
  83. template<typename T>
  84. class circular_buffer {
  85. struct M {
  86. std::unique_ptr<char[]> buffer;
  87. size_t capacity;
  88. size_t start;
  89. size_t end;
  90. };
  91. M m;
  92. M null_members() {
  93. return M{
  94. .buffer = nullptr,
  95. .capacity = 0,
  96. .start = 0,
  97. .end = 0
  98. };
  99. }
  100. static size_t validate_capacity(size_t new_capacity) {
  101. if (new_capacity < 2) return 2;
  102. if ((new_capacity bitand (new_capacity - 1))) {
  103. new_capacity = new_capacity & (new_capacity >> 1);
  104. new_capacity = new_capacity & (new_capacity >> 2);
  105. new_capacity = new_capacity & (new_capacity >> 4);
  106. new_capacity = new_capacity & (new_capacity >> 8);
  107. new_capacity = new_capacity & (new_capacity >> 16);
  108. new_capacity = new_capacity & (new_capacity >> 31);
  109. return new_capacity + 1;
  110. }
  111. return new_capacity;
  112. }
  113. explicit circular_buffer(M s) : m(std::move(s)) {}
  114. public:
  115. circular_buffer()
  116. : m{null_members()} {}
  117. circular_buffer(const circular_buffer &oth)
  118. : m(null_members()) {
  119. if (oth.m.capacity == 0) return;
  120. reserve(oth.m.capacity);
  121. for (const auto &elem: oth) {
  122. push_back(elem);
  123. }
  124. }
  125. circular_buffer(circular_buffer &&oth) noexcept
  126. : m{std::exchange(oth.m, null_members())} {}
  127. circular_buffer &operator=(const circular_buffer &oth) {
  128. if (this == &oth) return *this;
  129. while (pop_front());
  130. reserve(oth.m.capacity);
  131. for (const auto &elem: oth) {
  132. push_back(elem);
  133. }
  134. };
  135. circular_buffer &operator=(circular_buffer &&oth) noexcept {
  136. std::swap(m, oth.m);
  137. }
  138. circular_buffer_iterator<T> begin() {
  139. return circular_buffer_iterator<T>(reinterpret_cast<T *>(m.buffer.get()), m.capacity, m.start);
  140. }
  141. circular_buffer_iterator<T> end() {
  142. return circular_buffer_iterator<T>(reinterpret_cast<T *>(m.buffer.get()), m.capacity, m.end);
  143. }
  144. circular_buffer_iterator<const T> begin() const {
  145. return circular_buffer_iterator<const T>{
  146. m.buffer.get(), m.capacity, m.start
  147. };
  148. }
  149. circular_buffer_iterator<const T> end() const {
  150. return circular_buffer_iterator<const T>{
  151. m.buffer.get(), m.capacity, m.end
  152. };
  153. }
  154. void reserve(size_t new_capacity) {
  155. new_capacity = validate_capacity(new_capacity);
  156. if (new_capacity <= m.capacity) return;
  157. circular_buffer temp{M{
  158. .buffer = std::make_unique<char[]>(new_capacity * sizeof(T)),
  159. .capacity = new_capacity,
  160. .start = 0,
  161. .end = 0
  162. }};
  163. _details::optional <T> value = pop_front();
  164. while (value) {
  165. temp.push_back(std::move(value.value()));
  166. value = pop_front();
  167. }
  168. std::swap(m, temp.m);
  169. }
  170. void push_front(T value) {
  171. if (m.capacity == 0) reserve(2);
  172. size_t new_start = (m.start - 1) bitand (m.capacity - 1);
  173. if (new_start == m.end) {
  174. reserve(m.capacity << 1);
  175. }
  176. new_start = (m.start - 1) bitand (m.capacity - 1);
  177. ::new(reinterpret_cast<T *>(m.buffer.get()) + new_start) T(value);
  178. m.start = new_start;
  179. }
  180. _details::optional <T> pop_front() noexcept {
  181. if (m.start == m.end) return _details::nullopt;
  182. _details::optional <T> ret = std::move(*begin());
  183. (*begin()).~T();
  184. m.start = (m.start + 1) bitand (m.capacity - 1);
  185. return ret;
  186. }
  187. void push_back(T value) {
  188. if (m.capacity == 0) reserve(2);
  189. size_t new_end = (m.end + 1) bitand (m.capacity - 1);
  190. if (new_end == m.start) {
  191. reserve(m.capacity << 1);
  192. }
  193. new_end = (m.end + 1) bitand (m.capacity - 1);
  194. ::new(reinterpret_cast<T *>(m.buffer.get()) + m.end) T(value);
  195. m.end = new_end;
  196. }
  197. _details::optional <T> pop_back() noexcept {
  198. if (m.start == m.end) return _details::nullopt;
  199. auto last = --end();
  200. _details::optional <T> ret = std::move(*last);
  201. (*last).~T();
  202. m.end = (m.end - 1) bitand (m.capacity - 1);
  203. return ret;
  204. }
  205. bool empty() const {
  206. return m.start == m.end;
  207. }
  208. ~circular_buffer() {
  209. while (not empty()) {
  210. pop_front();
  211. }
  212. }
  213. };
  214. }
  215. namespace _details {
  216. template<typename T>
  217. class channel_impl {
  218. mutable std::mutex lock;
  219. container::circular_buffer<T> data;
  220. int active_writer = 0;
  221. int active_reader = 0;
  222. public:
  223. struct reader_t{};
  224. struct writer_t{};
  225. static constexpr reader_t reader{};
  226. static constexpr writer_t writer{};
  227. void close(reader_t) {
  228. std::lock_guard<std::mutex> d{lock};
  229. active_reader -= 1;
  230. }
  231. void close(writer_t) {
  232. std::lock_guard<std::mutex> d{lock};
  233. active_writer -=1;
  234. }
  235. void register_one(reader_t, _details::_do_not_use_t) {
  236. std::lock_guard<std::mutex> d{lock};
  237. active_reader += 1;
  238. }
  239. void register_one(writer_t, _details::_do_not_use_t) {
  240. std::lock_guard<std::mutex> d{lock};
  241. active_writer += 1;
  242. }
  243. bool closed(reader_t) {
  244. std::lock_guard<std::mutex> d{lock};
  245. return active_reader == 0;
  246. }
  247. bool closed(writer_t) {
  248. std::lock_guard<std::mutex> d{lock};
  249. return active_writer == 0;
  250. }
  251. bool push(const T& elem) {
  252. std::lock_guard<std::mutex> d{lock};
  253. if(active_reader == 0) return true;
  254. if(active_writer == 0) return false;
  255. data.push_front(elem);
  256. return true;
  257. }
  258. bool push(T&& elem) {
  259. std::lock_guard<std::mutex> d{lock};
  260. if(active_reader == 0) return true;
  261. if(active_writer == 0) return false;
  262. data.push_front(elem);
  263. return true;
  264. }
  265. _details::optional<T> pop() {
  266. std::lock_guard<std::mutex> d{lock};
  267. if(active_reader == 0) return _details::nullopt;
  268. return data.pop_back();
  269. }
  270. bool empty() const {
  271. return active_writer == 0 && data.empty();
  272. }
  273. };
  274. }
  275. /**
  276. * This is a read only channel of its specified template parameter type
  277. * @tparam T The type of element that is transmitted through the channel
  278. */
  279. template<typename T>
  280. class channel_r {
  281. std::shared_ptr<_details::channel_impl<T>> impl;
  282. public:
  283. /**
  284. * This constructor should **NOT** be used
  285. */
  286. channel_r(_details::_do_not_use_t, std::shared_ptr<_details::channel_impl<T>> _impl)
  287. : impl(_impl) {
  288. impl->register_one(_details::channel_impl<T>::reader, _details::do_not_use);
  289. }
  290. /**
  291. * Copy constructor for channel receiver
  292. */
  293. channel_r(const channel_r& oth) {
  294. if(oth.impl.get() == impl.get()) return;
  295. impl = oth.impl;
  296. if(impl) impl->register_one(_details::channel_impl<T>::reader, _details::do_not_use);
  297. }
  298. /**
  299. * Obtains a value from the queue
  300. * @return either a value if one is available in the queue, or no value
  301. */
  302. _details::optional<T> pop() {
  303. return impl->pop();
  304. }
  305. /**
  306. * Verifies if the queue is empty and has no sender available
  307. * @return true if the queue will never contain new elements
  308. * @return false if the queue may at some point in the future contain new elements
  309. */
  310. bool empty() const {
  311. return impl->empty();
  312. }
  313. ~channel_r() {
  314. impl->close(_details::channel_impl<T>::reader);
  315. }
  316. /**
  317. * Verifies if the writer side is still open
  318. * @return true if the writer side is closed
  319. * @return false if the writer side is still open
  320. */
  321. bool closed() {
  322. return impl->closed(_details::channel_impl<T>::writer);
  323. }
  324. };
  325. /**
  326. * This is a write only channel of its specified template parameter type
  327. * @tparam T The type of element that is transmitted through the channel
  328. */
  329. template<typename T>
  330. class channel_w {
  331. std::shared_ptr<_details::channel_impl<T>> impl;
  332. public:
  333. /**
  334. * This constructor should **NOT** be used
  335. */
  336. channel_w(_details::_do_not_use_t, std::shared_ptr<_details::channel_impl<T>> _impl)
  337. : impl(_impl) {
  338. impl->register_one(_details::channel_impl<T>::writer, _details::do_not_use);
  339. }
  340. /**
  341. * Copy constructor for channel sender
  342. */
  343. channel_w(const channel_w& oth) {
  344. if(oth.impl.get() == impl.get()) return;
  345. impl = oth.impl;
  346. if(impl) impl->register_one(_details::channel_impl<T>::writer, _details::do_not_use);
  347. }
  348. /**
  349. * Sends an element through the channel
  350. * @param elem the element to send
  351. * @return true is the element was successfully pushed
  352. */
  353. bool push(const T& elem) {
  354. return impl->push(elem);
  355. }
  356. /**
  357. * Sends an element through the channel
  358. * @param elem the element to send
  359. * @return true is the element was successfully pushed
  360. */
  361. bool push(T&& elem) {
  362. return impl->push(std::forward<T>(elem));
  363. }
  364. ~channel_w() {
  365. impl->close(_details::channel_impl<T>::writer);
  366. }
  367. /**
  368. * Verifies if the reader side is still open
  369. * @return true if the reader side is closed
  370. * @return false if the reader side is still open
  371. */
  372. bool closed() {
  373. return impl->closed(_details::channel_impl<T>::reader);
  374. }
  375. };
  376. /**
  377. * Creates a pipe made of a reader channel and a writer channel allowing to transmit objects of the specified type between units of concurrency
  378. * @tparam T The type to allow transfers of
  379. * @return a pair `[writer, reader]` that are connected
  380. */
  381. template<typename T>
  382. std::pair<channel_w<T>, channel_r<T>> make_pipe() {
  383. auto shared_ch = std::make_shared<_details::channel_impl<T>>();
  384. return {{_details::do_not_use, shared_ch}, {_details::do_not_use, shared_ch}};
  385. }
  386. template<typename T, typename awaiter = _details::awaiter>
  387. class promise;
  388. /**
  389. * This class allows instantiation and manipulation of the receiving side of a promise
  390. * @tparam T The type that will be received
  391. * @tparam awaiter A type that has an `operator()(int)` that represent how this object must wait
  392. */
  393. template<typename T, typename awaiter = _details::awaiter>
  394. class future {
  395. channel_r<T> conduit;
  396. friend class promise<T, awaiter>;
  397. future(channel_r<T>&& c) : conduit(c) {};
  398. public:
  399. /**
  400. * Waits for the future to be set
  401. */
  402. void wait() {
  403. for(;;) {
  404. if (conduit.closed()) return;
  405. awaiter{}(30);
  406. }
  407. }
  408. /**
  409. * Obtains the received value.
  410. *
  411. * @note This method should never be called before wait, and should not be called more than once
  412. * @return
  413. */
  414. _details::optional<T> get() {
  415. return conduit.pop();
  416. }
  417. };
  418. /**
  419. * This class allows to represent waiting for a value from one unit of concurrency into another one.
  420. * @tparam T The type of the value that will be transmitted
  421. * @tparam awaiter A type that has an `operator()(int)` that represent how `future`s created by this object must wait
  422. */
  423. template<typename T, typename awaiter>
  424. class promise {
  425. _details::optional<channel_w<T>> conduit;
  426. _details::optional<channel_r<T>> future_conduit;
  427. public:
  428. /**
  429. * Initializes a valid promise
  430. */
  431. promise() {
  432. auto pipe = make_pipe<T>();
  433. conduit = std::move(pipe.first);
  434. future_conduit = std::move(pipe.second);
  435. }
  436. /**
  437. * Obtains the receiving end of this promise
  438. *
  439. * @note This method should never be called more than once
  440. * @return A future that can be awaited from
  441. */
  442. future<T, awaiter> get_future() {
  443. defer(cleanup, future_conduit = _details::nullopt);
  444. return future<T, awaiter> {
  445. std::move(future_conduit.value())
  446. };
  447. }
  448. /**
  449. * Sets the value of the future to the provided value
  450. *
  451. * @note This method and methods sharing the same name should never be called more than once
  452. * @param value The value to transmit
  453. */
  454. void set_value(T&& value) {
  455. conduit.value().push(std::forward<T>(value));
  456. conduit = _details::nullopt;
  457. }
  458. /**
  459. * Sets the value of the future to the provided value
  460. *
  461. * @note This method and methods sharing the same name should never be called more than once
  462. * @param value The value to transmit
  463. */
  464. void set_value(const T& value) {
  465. conduit.value().push(value);
  466. conduit = _details::nullopt;
  467. }
  468. };
  469. #undef defer