A bunch of random code samples
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

533 rindas
13 KiB

pirms 3 mēnešiem
  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