stack.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /* Declarations for the stack template type.
  2. This file is part of xrcu.
  3. xrcu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #ifndef __XRCU_STACK_HPP__
  14. #define __XRCU_STACK_HPP__ 1
  15. #include "xrcu.hpp"
  16. #include "optional.hpp"
  17. #include <atomic>
  18. #include <cstddef>
  19. #include <utility>
  20. #include <initializer_list>
  21. namespace std
  22. {
  23. struct forward_iterator_tag;
  24. }
  25. namespace xrcu
  26. {
  27. namespace detail
  28. {
  29. struct stack_node_base
  30. {
  31. stack_node_base *next = nullptr;
  32. typedef std::atomic<stack_node_base *> ptr_type;
  33. static stack_node_base* root (const ptr_type& head);
  34. static void push (ptr_type& head, stack_node_base *nodep);
  35. static void push (ptr_type& head,
  36. stack_node_base *nodep, stack_node_base **outp);
  37. static stack_node_base* pop (ptr_type& head);
  38. static void swap (ptr_type& h1, ptr_type& h2);
  39. static stack_node_base* clear (ptr_type& head);
  40. static size_t size (const ptr_type& head);
  41. };
  42. struct stack_iter_base : public cs_guard
  43. {
  44. stack_node_base *runp;
  45. typedef std::forward_iterator_tag iterator_category;
  46. typedef ptrdiff_t difference_type;
  47. typedef size_t size_type;
  48. stack_iter_base (stack_node_base *rp) : runp (rp)
  49. {
  50. }
  51. stack_iter_base (const stack_iter_base& right) : runp (right.runp)
  52. {
  53. }
  54. stack_iter_base (stack_iter_base&& right) : runp (right.runp)
  55. {
  56. right.runp = nullptr;
  57. }
  58. void _Adv ()
  59. {
  60. this->runp = this->runp->next;
  61. }
  62. bool operator== (const stack_iter_base& right) const
  63. {
  64. return (this->runp == right.runp);
  65. }
  66. bool operator!= (const stack_iter_base& right) const
  67. {
  68. return (this->runp != right.runp);
  69. }
  70. };
  71. } // namespace detail.
  72. template <class T>
  73. struct stack
  74. {
  75. std::atomic<detail::stack_node_base *> hnode;
  76. struct _Stknode : public detail::stack_node_base, finalizable
  77. {
  78. T value;
  79. _Stknode (const T& v) : value (v)
  80. {
  81. }
  82. _Stknode (T&& v) : value (std::move (v))
  83. {
  84. }
  85. template <class ...Args>
  86. _Stknode (Args&&... args) : value (std::forward<Args>(args)...)
  87. {
  88. }
  89. void safe_destroy ()
  90. {
  91. auto runp = this->next;
  92. delete this;
  93. stack<T>::_Clean_nodes (runp);
  94. }
  95. };
  96. typedef _Stknode node_type;
  97. typedef T value_type;
  98. typedef T& reference;
  99. typedef const T& const_reference;
  100. typedef T* pointer;
  101. typedef const T* const_pointer;
  102. typedef ptrdiff_t difference_type;
  103. typedef size_t size_type;
  104. void _Reset (detail::stack_node_base *ptr)
  105. {
  106. this->hnode.store (ptr, std::memory_order_relaxed);
  107. }
  108. static void _Clean_nodes (detail::stack_node_base *runp)
  109. {
  110. while (runp)
  111. {
  112. auto tmp = runp->next;
  113. delete (node_type *)runp;
  114. runp = tmp;
  115. }
  116. }
  117. template <class T1>
  118. void _Init (T1 first, T1 last, std::false_type)
  119. {
  120. detail::stack_node_base *runp = nullptr, **outp = &runp;
  121. try
  122. {
  123. for (; first != last; ++first)
  124. {
  125. *outp = new node_type (*first);
  126. outp = &(*outp)->next;
  127. }
  128. }
  129. catch (...)
  130. {
  131. _Clean_nodes (runp);
  132. throw;
  133. }
  134. this->_Reset (runp);
  135. }
  136. template <class T1, class T2>
  137. void _Init (T1 n, const T2& value, std::true_type)
  138. {
  139. detail::stack_node_base *runp = nullptr, **outp = &runp;
  140. try
  141. {
  142. for (T1 x = 0; x != n; ++x)
  143. {
  144. *outp = new node_type (value);
  145. outp = &(*outp)->next;
  146. }
  147. }
  148. catch (...)
  149. {
  150. _Clean_nodes (runp);
  151. throw;
  152. }
  153. this->_Reset (runp);
  154. }
  155. stack ()
  156. {
  157. this->_Reset (nullptr);
  158. }
  159. template <class T1, class T2>
  160. stack (T1 first, T2 last)
  161. {
  162. this->_Reset (nullptr);
  163. this->_Init (first, last, typename std::is_integral<T1>::type ());
  164. }
  165. stack (std::initializer_list<T> lst) : stack (lst.begin (), lst.end ())
  166. {
  167. }
  168. stack (const stack<T>& right) : stack (right.begin (), right.end ())
  169. {
  170. }
  171. stack (stack<T>&& right)
  172. {
  173. this->_Reset (right._Root ());
  174. right._Reset (nullptr);
  175. }
  176. void push (const T& value)
  177. {
  178. cs_guard g;
  179. detail::stack_node_base::push (this->hnode, new node_type (value));
  180. }
  181. void push (T&& value)
  182. {
  183. cs_guard g;
  184. detail::stack_node_base::push (this->hnode,
  185. new node_type (std::move (value)));
  186. }
  187. template <class Iter>
  188. void _Push (Iter first, Iter last, std::false_type)
  189. {
  190. if (first == last)
  191. return;
  192. node_type *np;
  193. try
  194. {
  195. np = new node_type (*first);
  196. auto **outp = &np->next;
  197. for (++first; first != last; ++first)
  198. {
  199. node_type *tmp = new node_type (*first);
  200. *outp = tmp, outp = &tmp->next;
  201. }
  202. detail::stack_node_base::push (this->hnode, np, outp);
  203. }
  204. catch (...)
  205. {
  206. _Clean_nodes (np);
  207. throw;
  208. }
  209. }
  210. template <class T1, class T2>
  211. void _Push (T1 n, const T2& value, std::true_type)
  212. {
  213. if (n == 0)
  214. return;
  215. node_type *np;
  216. try
  217. {
  218. np = new node_type (value);
  219. auto **outp = &np->next;
  220. for (; n != 0; --n)
  221. {
  222. node_type *tmp = new node_type (value);
  223. *outp = tmp, outp = &tmp->next;
  224. }
  225. detail::stack_node_base::push (this->hnode, np, outp);
  226. }
  227. catch (...)
  228. {
  229. _Clean_nodes (np);
  230. throw;
  231. }
  232. }
  233. template <class T1, class T2>
  234. void push (T1 first, T2 last)
  235. {
  236. this->_Push (first, last, typename std::is_integral<T1>::type ());
  237. }
  238. template <class ...Args>
  239. void emplace (Args&& ...args)
  240. {
  241. detail::stack_node_base::push (this->hnode,
  242. new node_type (std::forward<Args>(args)...));
  243. }
  244. optional<T> pop ()
  245. {
  246. cs_guard g;
  247. auto node = detail::stack_node_base::pop (this->hnode);
  248. if (!node)
  249. return (optional<T> ());
  250. optional<T> ret { ((node_type *)node)->value };
  251. finalize ((node_type *)node);
  252. return (ret);
  253. }
  254. node_type* _Root ()
  255. {
  256. return ((node_type *)detail::stack_node_base::root (this->hnode));
  257. }
  258. node_type* _Root () const
  259. {
  260. return ((node_type *)detail::stack_node_base::root (this->hnode));
  261. }
  262. optional<T> top ()
  263. {
  264. cs_guard g;
  265. auto node = this->_Root ();
  266. return (node ? optional<T> { node->value } : optional<T> ());
  267. }
  268. struct iterator : public detail::stack_iter_base
  269. {
  270. typedef T value_type;
  271. typedef T& reference;
  272. typedef T* pointer;
  273. iterator (detail::stack_node_base *rp = nullptr) :
  274. detail::stack_iter_base (rp)
  275. {
  276. }
  277. iterator (const iterator& it) : detail::stack_iter_base (it)
  278. {
  279. }
  280. iterator (iterator&& it) : detail::stack_iter_base (std::move (it))
  281. {
  282. }
  283. T& operator* ()
  284. {
  285. return (((node_type *)this->runp)->value);
  286. }
  287. const T& operator* () const
  288. {
  289. return (((const node_type *)this->runp)->value);
  290. }
  291. T* operator-> ()
  292. {
  293. return (&**this);
  294. }
  295. const T* operator-> () const
  296. {
  297. return (&**this);
  298. }
  299. iterator& operator++ ()
  300. {
  301. this->_Adv ();
  302. return (*this);
  303. }
  304. iterator operator++ (int)
  305. {
  306. iterator tmp = { this->runp };
  307. this->_Adv ();
  308. return (tmp);
  309. }
  310. };
  311. typedef const iterator const_iterator;
  312. iterator begin ()
  313. {
  314. return (iterator (this->_Root ()));
  315. }
  316. iterator end ()
  317. {
  318. return (iterator ());
  319. }
  320. const_iterator cbegin () const
  321. {
  322. return (const_iterator (this->_Root ()));
  323. }
  324. const_iterator cend () const
  325. {
  326. return (const_iterator ());
  327. }
  328. const_iterator begin () const
  329. {
  330. return (this->cbegin ());
  331. }
  332. const_iterator end () const
  333. {
  334. return (this->cend ());
  335. }
  336. size_t size () const
  337. {
  338. cs_guard g;
  339. return (detail::stack_node_base::size (this->hnode));
  340. }
  341. size_t max_size () const
  342. {
  343. return (~(size_t)0);
  344. }
  345. bool empty () const
  346. {
  347. return (this->_Root () == nullptr);
  348. }
  349. void swap (stack<T>& right)
  350. {
  351. cs_guard g;
  352. if (this != &right)
  353. detail::stack_node_base::swap (this->hnode, right.hnode);
  354. }
  355. stack<T>& operator= (const stack<T>& right)
  356. {
  357. cs_guard g;
  358. if (this != &right)
  359. this->assign (right.begin (), right.end ());
  360. return (*this);
  361. }
  362. stack<T>& operator= (stack<T>&& right)
  363. {
  364. this->swap (right);
  365. finalize (right._Root ());
  366. right._Reset (nullptr);
  367. return (*this);
  368. }
  369. bool operator== (const stack<T>& right) const
  370. {
  371. auto x1 = this->cbegin (), x2 = this->cend ();
  372. auto y1 = right.cbegin (), y2 = right.cend ();
  373. for (; x1 != x2 && y1 != y2; ++x1, ++y1)
  374. if (*x1 != *y1)
  375. return (false);
  376. return (x1 == x2 && y1 == y2);
  377. }
  378. bool operator!= (const stack<T>& right) const
  379. {
  380. return (!(*this == right));
  381. }
  382. bool operator< (const stack<T>& right) const
  383. {
  384. auto x1 = this->cbegin (), x2 = this->cend ();
  385. auto y1 = right.cbegin (), y2 = right.cend ();
  386. for (; x1 != x2; ++x1, ++y1)
  387. {
  388. if (y1 == y2 || *y1 < *x1)
  389. return (false);
  390. else if (*x1 < *y1)
  391. return (true);
  392. }
  393. return (y1 != y2);
  394. }
  395. bool operator> (const stack<T>& right) const
  396. {
  397. return (right < *this);
  398. }
  399. bool operator<= (const stack<T>& right) const
  400. {
  401. return (!(right < *this));
  402. }
  403. bool operator>= (const stack<T>& right) const
  404. {
  405. return (!(*this < right));
  406. }
  407. void clear ()
  408. {
  409. auto prev = detail::stack_node_base::clear (this->hnode);
  410. finalize ((node_type *)prev);
  411. }
  412. template <class T1, class T2>
  413. void assign (T1 first, T2 last)
  414. {
  415. auto tmp = stack<T> (first, last);
  416. this->swap (tmp);
  417. finalize (tmp._Root ());
  418. tmp._Reset (nullptr);
  419. }
  420. void assign (std::initializer_list<T> lst)
  421. {
  422. this->assign (lst.begin (), lst.end ());
  423. }
  424. ~stack ()
  425. {
  426. auto tmp = this->_Root ();
  427. if (!tmp)
  428. return;
  429. _Clean_nodes (tmp);
  430. this->_Reset (nullptr);
  431. }
  432. };
  433. } // namespace xrcu
  434. namespace std
  435. {
  436. template <class T>
  437. void swap (xrcu::stack<T>& left, xrcu::stack<T>& right)
  438. {
  439. return (left.swap (right));
  440. }
  441. } // namespace std
  442. #endif