Galois
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gdeque.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_GDEQUE_H
21 #define GALOIS_GDEQUE_H
22 
23 #include "galois/config.h"
24 #include "galois/FixedSizeRing.h"
25 #include "galois/Mem.h"
27 
28 #include <boost/iterator/iterator_facade.hpp>
29 #include <boost/iterator/reverse_iterator.hpp>
30 
31 #include <algorithm>
32 #include <utility>
33 
34 namespace galois {
35 
36 // Experimental random access iterator. Slower than old iterator for simple
37 // traversals, so disable for now
38 //#define _NEW_ITERATOR
39 
41 template <typename T, unsigned ChunkSize = 64,
42  typename ContainerTy = FixedSizeRing<T, ChunkSize>>
43 class gdeque {
44 
45 protected:
46  struct Block : ContainerTy {
49 
50  Block() : next(), prev() {}
51 
52  template <typename InputIterator>
53  Block(InputIterator first, InputIterator second)
54  : ContainerTy(first, second), next(), prev() {}
55  };
56 
57 #ifdef _NEW_ITERATOR
58  template <typename U>
59  class outer_iterator
60  : public boost::iterator_facade<outer_iterator<U>, U,
61  boost::bidirectional_traversal_tag> {
62  friend class boost::iterator_core_access;
63  template <typename, unsigned, typename>
64  friend class gdeque;
65  Block* cur;
66  Block* last;
67 
68  void increment() { cur = cur->next; }
69  void decrement() {
70  if (cur) {
71  cur = cur->prev;
72  } else {
73  cur = last;
74  }
75  }
76 
77  template <typename OtherTy>
78  bool equal(const outer_iterator<OtherTy>& o) const {
79  return cur == o.cur;
80  }
81 
82  U& dereference() const { return *cur; }
83 
84  public:
85  outer_iterator(Block* b = 0, Block* l = 0) : cur(b), last(l) {}
86 
87  template <typename OtherTy>
88  outer_iterator(const outer_iterator<OtherTy>& o)
89  : cur(o.cur), last(o.last) {}
90  };
91 
92  typedef typename Block::iterator inner_iterator;
93  typedef typename Block::const_iterator const_inner_iterator;
94 #endif
95 
96  Block* first;
97 
98 private:
99  Block* last;
100  unsigned num;
101 
104 
105  template <typename... Args>
106  Block* alloc_block(Args&&... args) {
107  // Fixed size allocator can only allocate 1 object at a time of size
108  // sizeof(Block). Argument to allocate is always 1.
109  Block* b = heap.allocate(1);
110  return new (b) Block(std::forward<Args>(args)...);
111  }
112 
113  void free_block(Block* b) {
114  b->~Block();
115  heap.deallocate(b, 1);
116  }
118 
119  bool precondition() const {
120  return (num == 0 && first == NULL && last == NULL) ||
121  (num > 0 && first != NULL && last != NULL);
122  }
123 
124  Block* extend_first() {
125  Block* b = alloc_block();
126  b->next = first;
127  if (b->next)
128  b->next->prev = b;
129  first = b;
130  if (!last)
131  last = b;
132  return b;
133  }
134 
135  Block* extend_last() {
136  Block* b = alloc_block();
137  b->prev = last;
138  if (b->prev)
139  b->prev->next = b;
140  last = b;
141  if (!first)
142  first = b;
143  return b;
144  }
145 
146  void shrink(Block* b) {
147  if (b->next)
148  b->next->prev = b->prev;
149  if (b->prev)
150  b->prev->next = b->next;
151  if (b == first)
152  first = b->next;
153  if (b == last)
154  last = b->prev;
155  free_block(b);
156  }
157 
158  template <typename... Args>
159  std::pair<Block*, typename Block::iterator>
160  emplace(Block* b, typename Block::iterator ii, Args&&... args) {
161  ++num;
162  if (!b) {
163  // gdeque is empty or iteration == end
164  b = last;
165  if (!b || b->full())
166  b = extend_last();
167  ii = b->end();
168  } else if (b == first && ii == b->begin()) {
169  // iteration == begin
170  b = first;
171  if (!b || b->full())
172  b = extend_first();
173  ii = b->begin();
174  } else if (b->full()) {
175  auto d = std::distance(ii, b->end());
176  Block* n = alloc_block(std::make_move_iterator(ii),
177  std::make_move_iterator(b->end()));
178  for (; d > 0; --d)
179  b->pop_back();
180  ii = b->end();
181  n->next = b->next;
182  n->prev = b;
183  b->next = n;
184  if (b == last)
185  last = n;
186  }
187  unsigned boff = std::distance(b->begin(), ii);
188  b->emplace(ii, std::forward<Args>(args)...);
189  return std::make_pair(b, b->begin() + boff);
190  }
191 
192 public:
193 #ifdef _NEW_ITERATOR
194  typedef galois::TwoLevelIteratorA<outer_iterator<Block>, inner_iterator,
195  std::random_access_iterator_tag,
196  GetBegin<Block>, GetEnd<Block>>
197  iterator;
199  const_inner_iterator,
200  std::random_access_iterator_tag,
201  GetBegin<const Block>, GetEnd<const Block>>
203 #endif
204 #ifndef _NEW_ITERATOR
205  template <typename U>
206  struct Iterator
207  : public boost::iterator_facade<Iterator<U>, U,
208  boost::bidirectional_traversal_tag> {
210 
213  unsigned offset;
214 
215  private:
216  void increment() {
217  ++offset;
218  if (offset == b->size()) {
219  b = b->next;
220  offset = 0;
221  }
222  }
223 
224  void decrement() {
225  if (!b) {
226  b = last;
227  offset = b->size() - 1;
228  return;
229  } else if (offset == 0) {
230  b = b->prev;
231  offset = b->size() - 1;
232  } else {
233  --offset;
234  }
235  }
236 
237  template <typename OtherTy>
238  bool equal(const Iterator<OtherTy>& o) const {
239  return b == o.b && offset == o.offset;
240  }
241 
242  U& dereference() const { return b->getAt(offset); }
243 
244  public:
245  Iterator(Block* _b = 0, Block* _l = 0, unsigned _off = 0)
246  : b(_b), last(_l), offset(_off) {}
247 
248  template <typename OtherTy>
250  : b(o.b), last(o.last), offset(o.offset) {}
251  };
252  typedef Iterator<T> iterator;
253  typedef Iterator<const T> const_iterator;
254 #endif
255 
256  typedef boost::reverse_iterator<iterator> reverse_iterator;
257  typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
259  typedef typename iterator::pointer pointer;
260  typedef typename iterator::reference reference;
261  typedef typename const_iterator::reference const_reference;
262  typedef typename iterator::difference_type difference_type;
263  typedef size_t size_type;
264 
265  gdeque() : first(), last(), num(), heap() {}
266 
267  gdeque(gdeque&& o) : first(), last(), num(), heap() {
268  std::swap(first, o.first);
269  std::swap(last, o.last);
270  std::swap(num, o.num);
271  }
272 
274  std::swap(first, o.first);
275  std::swap(last, o.last);
276  std::swap(num, o.num);
277  return *this;
278  }
279 
280  gdeque(const gdeque&) = delete;
281  gdeque& operator=(const gdeque&) = delete;
282 
283  ~gdeque() { clear(); }
284 
286  assert(precondition());
287 
288 #ifdef _NEW_ITERATOR
289  return iterator{outer_iterator<Block>{first, last},
290  outer_iterator<Block>{nullptr, last},
291  outer_iterator<Block>{first, last}, GetBegin<Block>{},
292  GetEnd<Block>{}};
293 #else
294  return iterator{first, last, 0};
295 #endif
296  }
297 
299  assert(precondition());
300 #ifdef _NEW_ITERATOR
301  return iterator{outer_iterator<Block>{first, last},
302  outer_iterator<Block>{nullptr, last},
303  outer_iterator<Block>{nullptr, last}, GetBegin<Block>{},
304  GetEnd<Block>{}};
305 #else
306  return iterator{nullptr, last, 0};
307 #endif
308  }
309 
311  assert(precondition());
312 
313 #ifdef _NEW_ITERATOR
314  return const_iterator{outer_iterator<const Block>{first, last},
315  outer_iterator<const Block>{nullptr, last},
316  outer_iterator<const Block>{first, last},
319 #else
320  return const_iterator{first, last, 0};
321 #endif
322  }
323 
324  const_iterator end() const {
325 #ifdef _NEW_ITERATOR
326  return const_iterator{outer_iterator<const Block>{first, last},
327  outer_iterator<const Block>{nullptr, last},
328  outer_iterator<const Block>{nullptr, last},
331 #else
332  return const_iterator{nullptr, last, 0};
333 #endif
334  }
335 
337 
339 
341  return const_reverse_iterator{end()};
342  }
343 
345  return const_reverse_iterator{begin()};
346  }
347 
348  size_t size() const {
349  assert(precondition());
350  return num;
351  }
352 
353  bool empty() const {
354  assert(precondition());
355  return num == 0;
356  }
357 
359  assert(!empty());
360  return first->front();
361  }
362 
364  assert(!empty());
365  return first->front();
366  }
367 
369  assert(!empty());
370  return last->back();
371  }
372 
374  assert(!empty());
375  return last->back();
376  }
377 
378  void pop_back() {
379  assert(!empty());
380  --num;
381  last->pop_back();
382  if (last->empty())
383  shrink(last);
384  }
385 
386  void pop_front() {
387  assert(!empty());
388  --num;
389  first->pop_front();
390  if (first->empty())
391  shrink(first);
392  }
393 
394  void clear() {
395  assert(precondition());
396  Block* b = first;
397  while (b) {
398  b->clear();
399  Block* old = b;
400  b = b->next;
401  free_block(old);
402  }
403  first = last = NULL;
404  num = 0;
405  }
406 
408  template <typename... Args>
409  iterator emplace(iterator pos, Args&&... args) {
410 #ifdef _NEW_ITERATOR
411  Block* b = pos.get_outer_reference().cur;
412  inner_iterator ii = pos.get_inner_reference();
413 #else
414  Block* b = pos.b;
415  typename Block::iterator ii;
416  if (b)
417  ii = b->begin() + pos.offset;
418 #endif
419  auto p = emplace(b, ii, std::forward<Args>(args)...);
420 #ifdef _NEW_ITERATOR
421  return iterator{outer_iterator<Block>{first, last},
422  outer_iterator<Block>{nullptr, last},
423  outer_iterator<Block>{p.first, last},
424  p.second,
425  GetBegin<Block>{},
426  GetEnd<Block>{}};
427 #else
428  return iterator(p.first, last, std::distance(p.first->begin(), p.second));
429 #endif
430  }
431 
433  GALOIS_DIE("not yet implemented");
434  return pos;
435  }
436 
437 #ifdef _NEW_ITERATOR
438  reference operator[](size_t x) {
440  if (x == 0)
441  return front();
442  else if (x == num)
443  return back();
444  auto ii = begin();
445  std::advance(ii, x);
446  return *ii;
447  }
448 
450  const_reference operator[](size_t x) const {
451  if (x == 0)
452  return front();
453  else if (x == num)
454  return back();
455  auto ii = begin();
456  std::advance(ii, x);
457  return *ii;
458  }
459 #endif
460 
461  template <typename... Args>
462  void emplace_back(Args&&... args) {
463  assert(precondition());
464  ++num;
465  if (!last || last->full())
466  extend_last();
467 #ifndef NDEBUG
468  pointer p = last->emplace_back(std::forward<Args>(args)...);
469  assert(p);
470 #else
471  last->emplace_back(std::forward<Args>(args)...);
472 #endif
473  }
474 
475  template <typename ValueTy>
476  void push_back(ValueTy&& v) {
477  emplace_back(std::forward<ValueTy>(v));
478  }
479 
480  template <typename... Args>
481  void emplace_front(Args&&... args) {
482  assert(precondition());
483  ++num;
484  if (!first || first->full())
485  extend_first();
486  pointer p = first->emplace_front(std::forward<Args>(args)...);
487  assert(p);
488  }
489 
490  template <typename ValueTy>
491  void push_front(ValueTy&& v) {
492  emplace_front(std::forward<ValueTy>(v));
493  }
494 };
495 
496 #undef _NEW_ITERATOR
497 } // namespace galois
498 #endif
Alternate implementation of ChooseTwoLevelIterator.
Definition: TwoLevelIteratorA.h:40
void push_front(ValueTy &&v)
Definition: gdeque.h:491
Block()
Definition: gdeque.h:50
Iterator< T > iterator
Definition: gdeque.h:252
Block * first
Definition: gdeque.h:96
reverse_iterator rend()
Definition: gdeque.h:338
iterator::pointer pointer
Definition: gdeque.h:259
Helper functor, returns t.end()
Definition: TwoLevelIteratorA.h:383
size_t size_type
Definition: gdeque.h:263
Block * next
Definition: gdeque.h:47
Iterator< const T > const_iterator
Definition: gdeque.h:253
Definition: gdeque.h:206
gdeque(gdeque &&o)
Definition: gdeque.h:267
const_iterator::reference const_reference
Definition: gdeque.h:261
iterator::difference_type difference_type
Definition: gdeque.h:262
Block(InputIterator first, InputIterator second)
Definition: gdeque.h:53
size_t size() const
Definition: gdeque.h:348
iterator end()
Definition: gdeque.h:298
iterator::reference reference
Definition: gdeque.h:260
iterator erase(iterator pos)
Definition: gdeque.h:432
const_reference back() const
Definition: gdeque.h:373
reference back()
Definition: gdeque.h:368
gdeque & operator=(gdeque &&o)
Definition: gdeque.h:273
void emplace_front(Args &&...args)
Definition: gdeque.h:481
#define GALOIS_DIE(...)
Definition: gIO.h:96
bool empty() const
Definition: gdeque.h:353
void clear()
Definition: gdeque.h:394
Block * b
Definition: gdeque.h:211
void emplace_back(Args &&...args)
Definition: gdeque.h:462
const_reverse_iterator rbegin() const
Definition: gdeque.h:340
void push_back(ValueTy &&v)
Definition: gdeque.h:476
reference front()
Definition: gdeque.h:358
Block * last
Definition: gdeque.h:212
gdeque()
Definition: gdeque.h:265
~gdeque()
Definition: gdeque.h:283
void pop_front()
Definition: gdeque.h:386
void pop_back()
Definition: gdeque.h:378
iterator begin()
Definition: gdeque.h:285
reverse_iterator rbegin()
Definition: gdeque.h:336
Iterator(const Iterator< OtherTy > &o)
Definition: gdeque.h:249
boost::reverse_iterator< const_iterator > const_reverse_iterator
Definition: gdeque.h:257
const_iterator end() const
Definition: gdeque.h:324
unsigned offset
Definition: gdeque.h:213
const_reference front() const
Definition: gdeque.h:363
friend class boost::iterator_core_access
Definition: gdeque.h:209
iterator emplace(iterator pos, Args &&...args)
Invalidates pointers.
Definition: gdeque.h:409
Block * prev
Definition: gdeque.h:48
Definition: gdeque.h:46
Like std::deque but use Galois memory management functionality.
Definition: gdeque.h:43
T value_type
Definition: Executor_ParaMeter.h:111
iterator::value_type value_type
Definition: gdeque.h:258
const_reverse_iterator rend() const
Definition: gdeque.h:344
const_iterator begin() const
Definition: gdeque.h:310
A fixed size block allocator.
Definition: runtime/Mem.h:703
Iterator(Block *_b=0, Block *_l=0, unsigned _off=0)
Definition: gdeque.h:245
boost::reverse_iterator< iterator > reverse_iterator
Definition: gdeque.h:256
Helper functor, returns t.end()
Definition: TwoLevelIteratorA.h:391