Honeycomb  0.1
Component-Model Framework
List.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
6 
7 namespace honey
8 {
10 namespace lockfree
11 {
12 
14 
23 template<class T, class Alloc_ = SmallAllocator<T>, class Backoff = Backoff, uint8 iterMax = 2>
25 {
26  template<class> friend class HazardMem;
27 private:
28  struct Node : HazardMemNode
29  {
31  struct Link : HazardMemLink<Node>
32  {
34  static const intptr_t d_mask = 1;
35  static const intptr_t ptr_mask = ~d_mask;
36 
37  Link() { data = 0; }
38  Link(Node* ptr, bool d = false) { data = reinterpret_cast<intptr_t>(ptr) | (intptr_t)d; }
39  Node* ptr() const { return reinterpret_cast<Node*>(data & ptr_mask); }
40  bool d() const { return data & d_mask; }
41  bool cas(const Link& val, const Link& old) { return data.cas(val.data, old.data); }
42 
43  bool operator==(const Link& rhs) { return data == rhs.data; }
44  bool operator!=(const Link& rhs) { return !operator==(rhs); }
45  };
46 
47  template<class T_>
48  Node(T_&& val) : val(forward<T_>(val)) {}
49 
50  T val;
51  Link next;
52  Link prev;
53  };
54  typedef typename Node::Link Link;
55 
56 public:
57  typedef T value_type;
58  typedef Alloc_ Alloc;
59 
65  List(const Alloc& alloc = Alloc(), int threadMax = 10) :
66  _mem(*this, alloc, threadMax),
67  _size(0)
68  {
69  _mem.storeRef(_head, &createNode(T()));
70  _mem.storeRef(_tail, &createNode(T()));
71  _mem.storeRef(_head.ptr()->next, _tail);
72  _mem.storeRef(_tail.ptr()->prev, _head);
73  _mem.releaseRef(*_head.ptr());
74  _mem.releaseRef(*_tail.ptr());
75  }
76 
78  {
79  clear();
80  _mem.deleteNode(*_head.ptr());
81  _mem.deleteNode(*_tail.ptr());
82  }
83 
85  template<class T_>
86  void push_front(T_&& val)
87  {
88  Node& node = createNode(forward<T_>(val));
89  Node* prev = _mem.deRefLink(_head);
90  Node* next = _mem.deRefLink(prev->next);
91  _backoff.reset();
92  while (true)
93  {
94  _mem.storeRef(node.prev, prev);
95  _mem.storeRef(node.next, next);
96  if (_mem.casRef(prev->next, &node, next)) break;
97  _mem.releaseRef(*next);
98  next = _mem.deRefLink(prev->next);
99  _backoff.inc();
100  _backoff.wait();
101  }
102  ++_size;
103  _mem.releaseRef(*prev);
104  pushEnd(node, *next);
105  }
106 
108  template<class T_>
109  void push_back(T_&& val)
110  {
111  Node& node = createNode(forward<T_>(val));
112  Node* next = _mem.deRefLink(_tail);
113  Node* prev = _mem.deRefLink(next->prev);
114  _backoff.reset();
115  while (true)
116  {
117  _mem.storeRef(node.prev, prev);
118  _mem.storeRef(node.next, next);
119  if (_mem.casRef(prev->next, &node, next)) break;
120  prev = &correctPrev(*prev, *next);
121  _backoff.inc();
122  _backoff.wait();
123  }
124  ++_size;
125  _mem.releaseRef(*prev);
126  pushEnd(node, *next);
127  }
128 
131  {
132  Node* prev = _mem.deRefLink(_head);
133  _backoff.reset();
134  while (true)
135  {
136  Node* node = _mem.deRefLink(prev->next);
137  if (node == _tail.ptr())
138  {
139  _mem.releaseRef(*node);
140  _mem.releaseRef(*prev);
141  return false;
142  }
143  bool next_d = node->next.d();
144  Node* next = _mem.deRefLink(node->next);
145  if (next_d)
146  {
147  setMark(node->prev);
148  _mem.casRef(prev->next, next, node);
149  _mem.releaseRef(*next);
150  _mem.releaseRef(*node);
151  continue;
152  }
153  if (_mem.casRef(node->next, Link(next,true), next))
154  {
155  --_size;
156  prev = &correctPrev(*prev, *next);
157  _mem.releaseRef(*prev);
158  _mem.releaseRef(*next);
159  if (val) val = move(node->val);
160  _mem.releaseRef(*node);
161  _mem.deleteNode(*node);
162  break;
163  }
164  _mem.releaseRef(*next);
165  _mem.releaseRef(*node);
166  _backoff.inc();
167  _backoff.wait();
168  }
169  return true;
170  }
171 
174  {
175  Node* next = _mem.deRefLink(_tail);
176  Node* node = _mem.deRefLink(next->prev);
177  _backoff.reset();
178  while (true)
179  {
180  if (node->next != Link(next))
181  {
182  node = &correctPrev(*node, *next);
183  continue;
184  }
185  if (node == _head.ptr())
186  {
187  _mem.releaseRef(*node);
188  _mem.releaseRef(*next);
189  return false;
190  }
191  if (_mem.casRef(node->next, Link(next,true), next))
192  {
193  --_size;
194  Node* prev = _mem.deRefLink(node->prev);
195  prev = &correctPrev(*prev, *next);
196  _mem.releaseRef(*prev);
197  _mem.releaseRef(*next);
198  if (val) val = move(node->val);
199  _mem.releaseRef(*node);
200  _mem.deleteNode(*node);
201  break;
202  }
203  _backoff.inc();
204  _backoff.wait();
205  }
206  return true;
207  }
208 
210 
214  template<class T_>
215  class Iter_
216  {
217  friend class List;
218 
219  public:
220  typedef std::bidirectional_iterator_tag iterator_category;
221  typedef T_ value_type;
223  typedef T_* pointer;
224  typedef T_& reference;
225 
226  Iter_() : _list(nullptr), _cur(nullptr) {}
227 
228  Iter_(const List& list, bool end) :
229  _list(const_cast<List*>(&list)),
230  _cur(!end ? _list->_head.ptr() : _list->_tail.ptr())
231  {
232  _list->_mem.ref(*_cur);
233  }
234 
235  Iter_(const Iter_& it) : _cur(nullptr) { operator=(it); }
236 
238  {
239  if (_cur) _list->_mem.releaseRef(*_cur);
240  }
241 
243  Iter_& operator=(const Iter_& it)
244  {
245  if (_cur) _list->_mem.releaseRef(*_cur);
246  _list = it._list;
247  _cur = it._cur;
248  if (_cur) _list->_mem.ref(*_cur);
249  return *this;
250  }
251 
253  {
254  while (true)
255  {
256  if (_cur == _list->_tail.ptr()) break;
257  Node* next = _list->_mem.deRefLink(_cur->next);
258  bool d = next->next.d();
259  if (d && _cur->next != Link(next, true))
260  {
261  _list->setMark(next->prev);
262  _list->_mem.casRef(_cur->next, next->next.ptr(), next);
263  _list->_mem.releaseRef(*next);
264  continue;
265  }
266  _list->_mem.releaseRef(*_cur);
267  _cur = next;
268  if (!d) break;
269  }
270  return *this;
271  }
272 
274  {
275  while (true)
276  {
277  if (_cur == _list->_head.ptr()) break;
278  Node* prev = _list->_mem.deRefLink(_cur->prev);
279  if (prev->next == Link(_cur) && !_cur->next.d())
280  {
281  _list->_mem.releaseRef(*_cur);
282  _cur = prev;
283  break;
284  }
285  else if (_cur->next.d())
286  {
287  _list->_mem.releaseRef(*prev);
288  operator++();
289  }
290  else
291  {
292  prev = &_list->correctPrev(*prev, *_cur);
293  _list->_mem.releaseRef(*prev);
294  }
295  }
296  return *this;
297  }
298 
299  Iter_ operator++(int) { auto tmp = *this; ++*this; return tmp; }
300  Iter_ operator--(int) { auto tmp = *this; --*this; return tmp; }
301 
302  bool operator==(const Iter_& rhs) const { return _cur == rhs._cur; }
303  bool operator!=(const Iter_& rhs) const { return !operator==(rhs); }
304 
305  reference operator*() const { return _cur->val; }
306  pointer operator->() const { return &operator*(); }
307 
309  bool valid() const { return !_cur->next.d(); }
310 
311  private:
312  List* _list;
313  Node* _cur;
314  };
315 
316  typedef Iter_<T> Iter;
318 
320  ConstIter begin() const { return ++ConstIter(*this, false); }
321  Iter begin() { return ++Iter(*this, false); }
322 
324  ConstIter end() const { return ConstIter(*this, true); }
325  Iter end() { return Iter(*this, true); }
326 
328  template<class T_>
329  class IterR_
330  {
331  friend class List;
332 
333  public:
334  typedef Iter_<T_> Iter;
335 
336  typedef std::bidirectional_iterator_tag iterator_category;
337  typedef T_ value_type;
339  typedef T_* pointer;
340  typedef T_& reference;
341 
342  IterR_(Iter& it = Iter()) : _it(it) {}
343 
344  IterR_& operator++() { --_it; return *this; }
345  IterR_& operator--() { ++_it; return *this; }
346  IterR_ operator++(int) { auto tmp = *this; ++*this; return tmp; }
347  IterR_ operator--(int) { auto tmp = *this; --*this; return tmp; }
348 
349  bool operator==(const IterR_& rhs) const { return _it == rhs._it; }
350  bool operator!=(const IterR_& rhs) const { return !operator==(rhs); }
351 
352  reference operator*() const { return *_it; }
353  pointer operator->() const { return _it.operator->(); }
354 
355  bool valid() const { return _it.valid(); }
356 
357  private:
358  Iter _it;
359  };
360 
361  typedef IterR_<T> IterR;
363 
365  ConstIterR rbegin() const { return --end(); }
366  IterR rbegin() { return --end(); }
367 
369  ConstIterR rend() const { return ConstIter(*this, false); }
370  IterR rend() { return Iter(*this, false); }
371 
373  bool front(T& val)
374  {
375  Iter it = begin();
376  if (it == end() || !it.valid()) return false;
377  val = *it;
378  return true;
379  }
380 
382  bool back(T& val)
383  {
384  IterR it = rbegin();
385  if (it == rend() || !it.valid()) return false;
386  val = *it;
387  return true;
388  }
389 
391  template<class T_>
392  Iter insert(const Iter& it, T_&& val)
393  {
394  Iter pos = it;
395  assert(pos._cur != _head.ptr());
396 
397  Node& node = createNode(forward<T_>(val));
398  Node* prev = _mem.deRefLink(pos._cur->prev);
399  Node* next = nullptr;
400  _backoff.reset();
401  while (true)
402  {
403  while (pos._cur->next.d())
404  {
405  ++pos;
406  prev = &correctPrev(*prev, *pos._cur);
407  }
408  next = pos._cur;
409  _mem.storeRef(node.prev, prev);
410  _mem.storeRef(node.next, next);
411  if (_mem.casRef(prev->next, &node, pos._cur)) break;
412  prev = &correctPrev(*prev, *pos._cur);
413  _backoff.inc();
414  _backoff.wait();
415  }
416  ++_size;
417  _mem.releaseRef(*prev);
418  //correctPrev takes control of our node ref, so add another ref then release the node returned.
419  _mem.ref(node);
420  _mem.releaseRef(correctPrev(node, *next));
421  _mem.releaseRef(*next);
422  pos._cur = &node;
423  return pos;
424  }
425 
427  bool erase(Iter& it, optional<T&> val = optnull)
428  {
429  bool erased = false;
430  Node* node = it._cur;
431  assert(node != _head.ptr() && node != _tail.ptr());
432  while (true)
433  {
434  bool next_d = it._cur->next.d();
435  Node* next = _mem.deRefLink(it._cur->next);
436  if (next_d)
437  {
438  _mem.releaseRef(*next);
439  break;
440  }
441  if (node->next.cas(Link(next, true), next))
442  {
443  erased = true;
444  --_size;
445  Node* prev = nullptr;
446  while (true)
447  {
448  bool bPrev = node->prev.d();
449  prev = _mem.deRefLink(node->prev);
450  if (bPrev || node->prev.cas(Link(prev, true), prev)) break;
451  _mem.releaseRef(*prev);
452  }
453  prev = &correctPrev(*prev, *next);
454  _mem.releaseRef(*prev);
455  _mem.releaseRef(*next);
456  if (val) val = move(node->val);
457  _mem.deleteNode(*node);
458  break;
459  }
460  _mem.releaseRef(*next);
461  }
462  ++it;
463  return erased;
464  }
465 
467  void clear() { for (Iter it = begin(); it != end();) erase(it); }
468 
470  bool empty() const { return !size(); }
472  szt size() const { sdt size = _size; return size > 0 ? size : 0; } //Size can be less than 0 temporarily because of concurrency
473 
474 private:
476  static const uint8 linkMax = 2;
478  static const uint8 linkDelMax = linkMax;
480  static const uint8 hazardMax = 5 + iterMax;
481 
483  void cleanUpNode(Node& node)
484  {
485  while (true)
486  {
487  Node* prev = _mem.deRefLink(node.prev);
488  if (!prev) break;
489  if (!prev->prev.d())
490  {
491  _mem.releaseRef(*prev);
492  break;
493  }
494  Node* prev2 = _mem.deRefLink(prev->prev);
495  _mem.casRef(node.prev, Link(prev2, true), Link(prev, true));
496  _mem.releaseRef(*prev2);
497  _mem.releaseRef(*prev);
498  }
499  while (true)
500  {
501  Node* next = _mem.deRefLink(node.next);
502  if (!next) break;
503  if (!next->next.d())
504  {
505  _mem.releaseRef(*next);
506  break;
507  }
508  Node* next2 = _mem.deRefLink(next->next);
509  _mem.casRef(node.next, Link(next2, true), Link(next, true));
510  _mem.releaseRef(*next2);
511  _mem.releaseRef(*next);
512  }
513  }
514 
516  void terminateNode(Node& node, bool concurrent)
517  {
518  if (!concurrent)
519  {
520  _mem.storeRef(node.prev, Link(nullptr, true));
521  _mem.storeRef(node.next, Link(nullptr, true));
522  }
523  else
524  {
525  _mem.casRef(node.prev, Link(nullptr, true), Link(node.prev));
526  _mem.casRef(node.next, Link(nullptr, true), Link(node.next));
527  }
528  }
529 
530  template<class T_>
531  Node& createNode(T_&& val)
532  {
533  Node& node = _mem.createNode(forward<T_>(val));
534  assert((reinterpret_cast<intptr_t>(&node) & ~Link::ptr_mask) == 0, "Pointer not 2-byte aligned, bits found outside mask.");
535  return node;
536  }
537 
539  void setMark(Link& link)
540  {
541  while (true)
542  {
543  Link old = link;
544  if (old.d() || link.cas(Link(old.ptr(), true), old)) break;
545  }
546  }
547 
549  void pushEnd(Node& node, Node& next)
550  {
551  Node* pNode = &node;
552  _backoff.reset();
553  while (true)
554  {
555  Link link = next.prev;
556  if (link.d() || node.next != Link(&next)) break;
557  if (_mem.casRef(next.prev, &node, link))
558  {
559  if (node.prev.d())
560  pNode = &correctPrev(node, next);
561  break;
562  }
563  _backoff.inc();
564  _backoff.wait();
565  }
566  _mem.releaseRef(next);
567  _mem.releaseRef(*pNode);
568  }
569 
571  Node& correctPrev(Node& prev_, Node& node)
572  {
573  Node* prev = &prev_;
574  Node* lastLink = nullptr;
575  _backoffCp.reset();
576  while (true)
577  {
578  Link link = node.prev;
579  if (link.d())
580  {
581  //node was deleted while correcting, prev may have advanced past node, so undo the last step
582  if (lastLink)
583  {
584  _mem.releaseRef(*prev);
585  prev = lastLink;
586  lastLink = nullptr;
587  }
588  break;
589  }
590  bool prev2_d = prev->next.d();
591  Node* prev2 = _mem.deRefLink(prev->next);
592  if (prev2_d)
593  {
594  if (lastLink)
595  {
596  setMark(prev->prev);
597  _mem.casRef(lastLink->next, prev2, prev);
598  _mem.releaseRef(*prev2);
599  _mem.releaseRef(*prev);
600  prev = lastLink;
601  lastLink = nullptr;
602  continue;
603  }
604  _mem.releaseRef(*prev2);
605  prev2 = _mem.deRefLink(prev->prev);
606  _mem.releaseRef(*prev);
607  prev = prev2;
608  continue;
609  }
610  if (prev2 != &node)
611  {
612  if (lastLink) _mem.releaseRef(*lastLink);
613  lastLink = prev;
614  prev = prev2;
615  continue;
616  }
617  _mem.releaseRef(*prev2);
618  if (_mem.casRef(node.prev, prev, link))
619  {
620  if (prev->prev.d()) continue;
621  break;
622  }
623  _backoffCp.inc();
624  _backoffCp.wait();
625  }
626  if (lastLink) _mem.releaseRef(*lastLink);
627  return *prev;
628  }
629 
630  HazardMem<List> _mem;
631  Link _head;
632  Link _tail;
633  Atomic<sdt> _size;
634  Backoff _backoff;
635  Backoff _backoffCp;
636 };
637 
638 } }
ConstIter begin() const
Get iterator to the beginning of the list.
Definition: List.h:320
Base node class, inherit from this class, add link members, and use as Node type in HazardMemConfig...
Definition: HazardMem.h:12
void clear()
Remove all elements.
Definition: List.h:467
bool empty() const
Check whether the list does not contain any elements.
Definition: List.h:470
Iterator.
Definition: List.h:215
IterR_ & operator++()
Definition: List.h:344
bool operator!=(const Iter_ &rhs) const
Definition: List.h:303
Iter_ & operator=(const Iter_ &it)
Copy iterator, must reference copied cursor.
Definition: List.h:243
T_ value_type
Definition: List.h:221
std::bidirectional_iterator_tag iterator_category
Definition: List.h:336
static optnull_t optnull
Null optional, use to reset an optional to an uninitialized state or test for initialization.
Definition: Optional.h:12
Iter_ & operator--()
Definition: List.h:273
List(const Alloc &alloc=Alloc(), int threadMax=10)
Definition: List.h:65
bool operator!=(const IterR_ &rhs) const
Definition: List.h:350
pointer operator->() const
Definition: List.h:353
sdt difference_type
Definition: List.h:338
Iter_< const T > ConstIter
Definition: List.h:317
ptrdiff_t sdt
Size difference type, shorthand for ptrdiff_t.
Definition: Core.h:92
Inherit to declare that class is not copyable.
Definition: Meta.h:286
Iter_ operator--(int)
Definition: List.h:300
bool pop_front(optional< T & > val=optnull)
Remove element from the beginning of the list and move it into val. Returns true on success...
Definition: List.h:130
void inc(int ticks=1)
Increase tick count by ticks. Increases the amount of time that backoff will wait.
Definition: Backoff.h:28
sdt difference_type
Definition: List.h:222
bool valid() const
Returns true if iterator points to valid element that has not been deleted.
Definition: List.h:309
void push_back(T_ &&val)
Add new element constructed with val onto the end of the list.
Definition: List.h:109
IterR rend()
Definition: List.h:370
bool front(T &val)
Get a copy of the element at the beginning of the list. Returns true on success, false if there is no...
Definition: List.h:373
Iter_ & operator++()
Definition: List.h:252
Iter_(const List &list, bool end)
Definition: List.h:228
bool operator==(const IterR_ &rhs) const
Definition: List.h:349
IterR_ operator++(int)
Definition: List.h:346
T_ * pointer
Definition: List.h:339
T value_type
Definition: List.h:57
T_ * pointer
Definition: List.h:223
T_ value_type
Definition: List.h:337
bool valid() const
Definition: List.h:355
unsigned char uint8
Definition: Core.h:12
szt size() const
Number of elements in list.
Definition: List.h:472
IterR rbegin()
Definition: List.h:366
Iter_ operator++(int)
Definition: List.h:299
~List()
Definition: List.h:77
bool operator==(const Iter_ &rhs) const
Definition: List.h:302
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
IterR_(Iter &it=Iter())
Definition: List.h:342
void push_front(T_ &&val)
Insert new element constructed with val at the beginning of the list.
Definition: List.h:86
bool erase(Iter &it, optional< T & > val=optnull)
Erase element at iterator position and move it into val, and advance iterator. Returns true if this t...
Definition: List.h:427
size_t szt
Size type, shorthand for size_t.
Definition: Core.h:90
T * alloc(szt count=1)
Allocate memory for count number of T objects. Objects are not constructed.
Definition: Allocator.h:31
Iter_< T_ > Iter
Definition: List.h:334
~Iter_()
Definition: List.h:237
Configuration interface for memory manager. Inherit this class and override types and static members...
Definition: HazardMem.h:32
pointer operator->() const
Definition: List.h:306
ConstIter end() const
Get iterator to the end of the list.
Definition: List.h:324
Iter end()
Definition: List.h:325
T_ & reference
Definition: List.h:224
IterR_< const T > ConstIterR
Definition: List.h:362
bool back(T &val)
Get a copy of the element the end of the list. Returns true on success, false if there is no element...
Definition: List.h:382
Specialization for references.
Definition: Optional.h:132
T_ & reference
Definition: List.h:340
ConstIterR rend() const
Get reverse iterator to the beginning of the list.
Definition: List.h:369
Reverse iterator.
Definition: List.h:329
Iter begin()
Definition: List.h:321
ConstIterR rbegin() const
Get reverse iterator to the end of the list.
Definition: List.h:365
reference operator*() const
Definition: List.h:305
IterR_ & operator--()
Definition: List.h:345
Alloc_ Alloc
Definition: List.h:58
HazardMemNode Node
Definition: HazardMem.h:34
Iter_()
Definition: List.h:226
Iter_< T > Iter
Definition: List.h:316
Lock-free memory manager, provides safe memory reclamation for concurrent algorithms.
Definition: HazardMem.h:57
void wait()
Perform backoff, suspend thread.
Definition: Backoff.h:56
void reset()
Reset backoff to initial state.
Definition: Backoff.h:59
IterR_< T > IterR
Definition: List.h:361
Iter_(const Iter_ &it)
Definition: List.h:235
std::bidirectional_iterator_tag iterator_category
Definition: List.h:220
Iter insert(const Iter &it, T_ &&val)
Insert new element constructed with val before iterator position. Returns iterator pointing to new el...
Definition: List.h:392
Global Honeycomb namespace.
Lock-free doubly-linked list.
Definition: List.h:24
bool pop_back(optional< T & > val=optnull)
Remove element from the end of the list and move it into val. Returns true on success, false if there is no element to pop.
Definition: List.h:173
reference operator*() const
Definition: List.h:352
IterR_ operator--(int)
Definition: List.h:347