Galois
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gslist.h
Go to the documentation of this file.
1 /*
2  * This file belongs to the Galois project, a C++ library for exploiting
3  * parallelism. The code is being released under the terms of the 3-Clause BSD
4  * License (a copy is located in LICENSE.txt at the top-level directory).
5  *
6  * Copyright (C) 2018, The University of Texas at Austin. All rights reserved.
7  * UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS
8  * SOFTWARE AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY,
9  * FITNESS FOR ANY PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF
10  * PERFORMANCE, AND ANY WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF
11  * DEALING OR USAGE OF TRADE. NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH
12  * RESPECT TO THE USE OF THE SOFTWARE OR DOCUMENTATION. Under no circumstances
13  * shall University be liable for incidental, special, indirect, direct or
14  * consequential damages or loss of profits, interruption of business, or
15  * related expenses which may arise from use of Software or Documentation,
16  * including but not limited to those resulting from defects in Software and/or
17  * Documentation, or loss or inaccuracy of data of any kind.
18  */
19 
20 #ifndef GALOIS_GSLIST_H
21 #define GALOIS_GSLIST_H
22 
23 #include <type_traits>
24 
25 #include <boost/iterator/iterator_facade.hpp>
26 #include <boost/mpl/if.hpp>
27 
28 #include "galois/config.h"
29 #include "galois/FixedSizeRing.h"
31 
32 namespace galois {
33 
34 template <typename T, int ChunkSize, bool Concurrent>
35 class gslist_base {
36 public:
39  struct promise_to_dealloc {};
40 
41 private:
42  typedef typename boost::mpl::if_c<Concurrent,
44  FixedSizeBag<T, ChunkSize>>::type Ring;
45 
46  struct Block : public Ring {
47  Block* next;
48  Block() : next() {}
49  };
50 
51  template <typename U>
52  class outer_iterator
53  : public boost::iterator_facade<outer_iterator<U>, U,
54  boost::forward_traversal_tag> {
55  friend class boost::iterator_core_access;
56  U* cur;
57 
58  void increment() { cur = cur->next; }
59 
60  template <typename OtherTy>
61  bool equal(const outer_iterator<OtherTy>& o) const {
62  return cur == o.cur;
63  }
64 
65  U& dereference() const { return *cur; }
66 
67  public:
68  outer_iterator(U* c = 0) : cur(c) {}
69 
70  template <typename OtherTy>
71  outer_iterator(const outer_iterator<OtherTy>& o) : cur(o.cur) {}
72  };
73 
74  typedef
75  typename boost::mpl::if_c<Concurrent, std::atomic<Block*>, Block*>::type
76  First;
77 
78  First first;
79 
80  template <typename HeapTy>
81  Block* alloc_block(HeapTy& heap) {
82  return new (heap.allocate(sizeof(Block))) Block();
83  }
84 
85  template <typename HeapTy>
86  void free_block(HeapTy& heap, Block* b) {
87  b->~Block();
88  heap.deallocate(b);
89  }
90 
91  void free_block(promise_to_dealloc, Block* b) { b->~Block(); }
92 
93  template <typename HeapTy, bool C = Concurrent>
94  auto extend_first(HeapTy& heap) -> typename std::enable_if<C>::type {
95  Block* b = alloc_block(heap);
96  while (true) {
97  Block* f = first.load(std::memory_order_relaxed);
98  b->next = f;
99  if (first.compare_exchange_weak(f, b))
100  return;
101  }
102  }
103 
104  template <typename HeapTy, bool C = Concurrent>
105  auto extend_first(HeapTy& heap) -> typename std::enable_if<!C>::type {
106  Block* b = alloc_block(heap);
107  b->next = first;
108  first = b;
109  }
110 
111  Block* get_first() {
112  Block* b = first;
113  return b;
114  }
115 
116  const Block* get_first() const {
117  Block* b = first;
118  return b;
119  }
120 
121  template <typename U, bool C = Concurrent>
122  auto shrink_first(Block* old_first, U&& arg) ->
123  typename std::enable_if<C>::type {
124  if (first.compare_exchange_strong(old_first, old_first->next)) {
125  // old_first->clear();
126  free_block(std::forward<U>(arg), old_first);
127  }
128  }
129 
130  template <typename U, bool C = Concurrent>
131  auto shrink_first(Block* old_first, U&& arg) ->
132  typename std::enable_if<!C>::type {
133  if (first != old_first)
134  return;
135  first = old_first->next;
136  // old_first->clear();
137  free_block(std::forward<U>(arg), old_first);
138  }
139 
140  template <typename U>
141  void _clear(U&& arg) {
142  Block* b = get_first();
143  while (b) {
144  shrink_first(b, std::forward<U>(arg));
145  b = get_first();
146  }
147  }
148 
149  template <typename U>
150  bool _pop_front(U&& arg) {
151  while (true) {
152  Block* b = get_first();
153  if (!b)
154  return false;
155  if (b->pop_front())
156  return true;
157 
158  shrink_first(b, std::forward<U>(arg));
159  }
160  }
161 
162 public:
164  typedef Block block_type;
165  typedef T value_type;
167  typename Block::iterator,
168  std::forward_iterator_tag, GetBegin, GetEnd>
171  typename Block::const_iterator,
172  std::forward_iterator_tag, GetBegin, GetEnd>
174 
175  gslist_base() : first(0) {}
176 
177  gslist_base(const gslist_base&) = delete;
178  gslist_base& operator=(const gslist_base&) = delete;
179 
180  gslist_base(gslist_base&& other) : first(0) { *this = std::move(other); }
181 
183  Block* m_first = first;
184  Block* o_first = o.first;
185  first = o_first;
186  o.first = m_first;
187  return *this;
188  }
189 
191  _clear(promise_to_dealloc());
192  // assert(empty() && "Memory leak if gslist is not empty before
193  // destruction");
194  }
195 
197  return galois::make_two_level_iterator(outer_iterator<Block>(get_first()),
198  outer_iterator<Block>(nullptr))
199  .first;
200  }
201 
203  return galois::make_two_level_iterator(outer_iterator<Block>(get_first()),
204  outer_iterator<Block>(nullptr))
205  .second;
206  }
207 
210  outer_iterator<const Block>(get_first()),
211  outer_iterator<const Block>(nullptr))
212  .first;
213  }
214 
215  const_iterator end() const {
217  outer_iterator<const Block>(get_first()),
218  outer_iterator<const Block>(nullptr))
219  .second;
220  }
221 
222  bool empty() const {
223  return first == NULL || (get_first()->empty() && get_first()->next == NULL);
224  }
225 
226  value_type& front() { return get_first()->front(); }
227 
228  const value_type& front() const { return get_first()->front(); }
229 
230  template <typename HeapTy, typename... Args, bool C = Concurrent>
231  auto emplace_front(HeapTy& heap, Args&&... args) ->
232  typename std::enable_if<!C>::type {
233  if (!first || first->full())
234  extend_first(heap);
235  first->emplace_front(std::forward<Args>(args)...);
236  }
237 
238  template <typename HeapTy, bool C = Concurrent>
239  auto push_front(HeapTy& heap, const value_type& v) ->
240  typename std::enable_if<C>::type {
241  while (true) {
242  Block* b = get_first();
243  if (b && b->push_front(v))
244  return;
245  extend_first(heap);
246  }
247  }
248 
249  template <typename HeapTy, typename ValueTy, bool C = Concurrent>
250  auto push_front(HeapTy& heap, ValueTy&& v) ->
251  typename std::enable_if<!C>::type {
252  emplace_front(heap, std::forward<ValueTy>(v));
253  }
254 
256  template <typename HeapTy>
257  bool pop_front(HeapTy& heap) {
258  return _pop_front(heap);
259  }
260 
263  return _pop_front(promise_to_dealloc());
264  }
265 
266  template <typename HeapTy>
267  void clear(HeapTy& heap) {
268  _clear(heap);
269  }
270 
272 };
273 
278 template <typename T, unsigned chunksize = 16>
280 
285 template <typename T, unsigned chunksize = 16>
287 
288 } // namespace galois
289 #endif
Alternate implementation of ChooseTwoLevelIterator.
Definition: TwoLevelIteratorA.h:40
iterator begin()
Definition: gslist.h:196
bool empty() const
Definition: gslist.h:222
Helper functor, returns t.end()
Definition: TwoLevelIteratorA.h:383
const_iterator begin() const
Definition: gslist.h:208
Unordered collection of bounded size.
Definition: FixedSizeRing.h:38
auto push_front(HeapTy &heap, const value_type &v) -> typename std::enable_if< C >::type
Definition: gslist.h:239
galois::TwoLevelIteratorA< outer_iterator< Block >, typename Block::iterator, std::forward_iterator_tag, GetBegin, GetEnd > iterator
Definition: gslist.h:169
gslist_base & operator=(const gslist_base &)=delete
gslist_base & operator=(gslist_base &&o)
Definition: gslist.h:182
const_iterator end() const
Definition: gslist.h:215
Tag for methods that depend on user to deallocate memory, although gslist will destroy elements...
Definition: gslist.h:39
auto push_front(HeapTy &heap, ValueTy &&v) -> typename std::enable_if<!C >::type
Definition: gslist.h:250
Definition: gslist.h:35
void clear(HeapTy &heap)
Definition: gslist.h:267
iterator end()
Definition: gslist.h:202
gslist_base(gslist_base &&other)
Definition: gslist.h:180
gslist_base()
Definition: gslist.h:175
std::pair< TwoLevelIteratorA< OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn >, TwoLevelIteratorA< OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn > > make_two_level_iterator(OuterIter outer_begin, OuterIter outer_end)
Definition: TwoLevelIteratorA.h:420
bool pop_front(HeapTy &heap)
Returns true if something was popped.
Definition: gslist.h:257
void clear(promise_to_dealloc)
Definition: gslist.h:271
T value_type
Definition: gslist.h:165
galois::TwoLevelIteratorA< outer_iterator< const Block >, typename Block::const_iterator, std::forward_iterator_tag, GetBegin, GetEnd > const_iterator
Definition: gslist.h:173
auto emplace_front(HeapTy &heap, Args &&...args) -> typename std::enable_if<!C >::type
Definition: gslist.h:231
~gslist_base()
Definition: gslist.h:190
const value_type & front() const
Definition: gslist.h:228
bool pop_front(promise_to_dealloc)
Returns true if something was popped.
Definition: gslist.h:262
Block block_type
External allocator must be able to allocate this type.
Definition: gslist.h:164
value_type & front()
Definition: gslist.h:226
Helper functor, returns t.end()
Definition: TwoLevelIteratorA.h:391