Galois
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Bag.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_BAG_H
21 #define GALOIS_BAG_H
22 
23 #include <algorithm>
24 #include <stdexcept>
25 
26 #include <boost/iterator/iterator_facade.hpp>
27 
28 #include "galois/config.h"
29 #include "galois/gstl.h"
32 #include "galois/gIO.h"
33 #include "galois/runtime/Mem.h"
34 
35 namespace galois {
36 
41 template <typename T, unsigned int BlockSize = 0>
42 class InsertBag {
43 
44  struct header {
45  header* next;
46  T* dbegin; // start of interesting data
47  T* dend; // end of valid data
48  T* dlast; // end of storage
49  };
50 
51  typedef std::pair<header*, header*> PerThread;
52 
53 public:
54  template <typename U>
55  class Iterator : public boost::iterator_facade<Iterator<U>, U,
56  boost::forward_traversal_tag> {
58 
60  unsigned int thr;
61  header* p;
62  U* v;
63 
64  bool init_thread() {
65  p = thr < hd->size() ? hd->getRemote(thr)->first : 0;
66  v = p ? p->dbegin : 0;
67  return p;
68  }
69 
70  bool advance_local() {
71  if (p) {
72  ++v;
73  return v != p->dend;
74  }
75  return false;
76  }
77 
78  bool advance_chunk() {
79  if (p) {
80  p = p->next;
81  v = p ? p->dbegin : 0;
82  }
83  return p;
84  }
85 
86  void advance_thread() {
87  while (thr < hd->size()) {
88  ++thr;
89  if (init_thread())
90  return;
91  }
92  }
93 
94  void increment() {
95  if (advance_local())
96  return;
97  if (advance_chunk())
98  return;
99  advance_thread();
100  }
101 
102  template <typename OtherTy>
103  bool equal(const Iterator<OtherTy>& o) const {
104  return hd == o.hd && thr == o.thr && p == o.p && v == o.v;
105  }
106 
107  U& dereference() const { return *v; }
108 
109  public:
110  Iterator() : hd(0), thr(0), p(0), v(0) {}
111 
112  template <typename OtherTy>
114  : hd(o.hd), thr(o.thr), p(o.p), v(o.v) {}
115 
117  galois::substrate::PerThreadStorage<std::pair<header*, header*>>* h,
118  unsigned t)
119  : hd(h), thr(t), p(0), v(0) {
120  // find first valid item
121  if (!init_thread())
122  advance_thread();
123  }
124  };
125 
126 private:
129 
130  void insHeader(header* h) {
131  PerThread& hpair = *heads.getLocal();
132  if (hpair.second) {
133  hpair.second->next = h;
134  hpair.second = h;
135  } else {
136  hpair.first = hpair.second = h;
137  }
138  }
139 
140  header* newHeaderFromHeap(void* m, unsigned size) {
141  header* H = new (m) header();
142  int offset = 1;
143  if (sizeof(T) < sizeof(header))
144  offset += sizeof(header) / sizeof(T);
145  T* a = reinterpret_cast<T*>(m);
146  H->dbegin = &a[offset];
147  H->dend = H->dbegin;
148  H->dlast = &a[(size / sizeof(T))];
149  H->next = 0;
150  return H;
151  }
152 
153  header* newHeader() {
154  if (BlockSize) {
155  return newHeaderFromHeap(heap.allocate(BlockSize), BlockSize);
156  } else {
157  return newHeaderFromHeap(galois::runtime::pagePoolAlloc(),
159  }
160  }
161 
162  void destruct_serial() {
163  for (unsigned x = 0; x < heads.size(); ++x) {
164  PerThread& hpair = *heads.getRemote(x);
165  header*& h = hpair.first;
166  while (h) {
167  uninitialized_destroy(h->dbegin, h->dend);
168  header* h2 = h;
169  h = h->next;
170  if (BlockSize)
171  heap.deallocate(h2);
172  else
174  }
175  hpair.second = 0;
176  }
177  }
178 
179  void destruct_parallel(void) {
181  [this](const unsigned int tid, const unsigned int) {
182  PerThread& hpair = *heads.getLocal(tid);
183  header*& h = hpair.first;
184  while (h) {
185  uninitialized_destroy(h->dbegin, h->dend);
186  header* h2 = h;
187  h = h->next;
188  if (BlockSize)
189  heap.deallocate(h2);
190  else
192  }
193  hpair.second = 0;
194  },
195  std::make_tuple(galois::no_stats()));
196  }
197 
198 public:
199  // static_assert(BlockSize == 0 || BlockSize >= (2 * sizeof(T) +
200  // sizeof(header)),
201  // "BlockSize should larger than sizeof(T) + O(1)");
202 
203  InsertBag() : heap(BlockSize) {}
204  InsertBag(InsertBag&& o) : heap(BlockSize) {
205  std::swap(heap, o.heap);
206  std::swap(heads, o.heads);
207  }
208 
210  std::swap(heap, o.heap);
211  std::swap(heads, o.heads);
212  return *this;
213  }
214 
215  InsertBag(const InsertBag&) = delete;
216  InsertBag& operator=(const InsertBag&) = delete;
217 
218  ~InsertBag() { destruct_parallel(); }
219 
220  void clear() { destruct_parallel(); }
221 
222  void clear_serial() { destruct_serial(); }
223 
224  void swap(InsertBag& o) {
225  std::swap(heap, o.heap);
226  std::swap(heads, o.heads);
227  }
228 
229  typedef T value_type;
230  typedef T* pointer;
231  typedef const T* const_pointer;
232  typedef const T& const_reference;
233  typedef T& reference;
234  typedef Iterator<T> iterator;
235  typedef Iterator<const T> const_iterator;
237 
238  iterator begin() { return iterator(&heads, 0); }
239  iterator end() { return iterator(&heads, heads.size()); }
240  const_iterator begin() const { return const_iterator(&heads, 0); }
241  const_iterator end() const { return const_iterator(&heads, heads.size()); }
242 
245  }
248  }
249 
250  bool empty() const {
251  for (unsigned x = 0; x < heads.size(); ++x) {
252  header* h = heads.getRemote(x)->first;
253  if (h)
254  return false;
255  }
256  return true;
257  }
259  template <typename... Args>
260  reference emplace(Args&&... args) {
261  header* H = heads.getLocal()->second;
262  T* rv;
263  if (!H || H->dend == H->dlast) {
264  H = newHeader();
265  insHeader(H);
266  }
267  rv = new (H->dend) T(std::forward<Args>(args)...);
268  ++H->dend;
269  return *rv;
270  }
271 
272  template <typename... Args>
273  reference emplace_back(Args&&... args) {
274  return emplace(std::forward<Args>(args)...);
275  }
276 
281  void pop() {
282  header* H = heads.getLocal()->second;
283  if (H->dbegin == H->dend) {
284  throw std::out_of_range("InsertBag::pop");
285  }
286  uninitialized_destroy(H->dend - 1, H->dend);
287  --H->dend;
288  }
289 
291  template <typename ItemTy>
292  reference push(ItemTy&& val) {
293  return emplace(std::forward<ItemTy>(val));
294  }
295 
297  template <typename ItemTy>
298  reference push_back(ItemTy&& val) {
299  return emplace(std::forward<ItemTy>(val));
300  }
301 };
302 
303 } // namespace galois
304 
305 #endif
Definition: Traits.h:247
const_iterator begin() const
Definition: Bag.h:240
reference push(ItemTy &&val)
Thread safe bag insertion.
Definition: Bag.h:292
~InsertBag()
Definition: Bag.h:218
InsertBag(InsertBag &&o)
Definition: Bag.h:204
reference emplace(Args &&...args)
Thread safe bag insertion.
Definition: Bag.h:260
iterator local_iterator
Definition: Bag.h:236
friend class boost::iterator_core_access
Definition: Bag.h:57
iterator begin()
Definition: Bag.h:238
Iterator(const Iterator< OtherTy > &o)
Definition: Bag.h:113
T * getLocal()
Definition: PerThreadStorage.h:128
reference emplace_back(Args &&...args)
Definition: Bag.h:273
local_iterator local_begin()
Definition: Bag.h:243
T & reference
Definition: Bag.h:233
Iterator()
Definition: Bag.h:110
void on_each_gen(FunctionTy &&fn, const TupleTy &tpl)
Definition: Executor_OnEach.h:74
void clear_serial()
Definition: Bag.h:222
iterator end()
Definition: Bag.h:239
Iterator< const T > const_iterator
Definition: Bag.h:235
const T & const_reference
Definition: Bag.h:232
size_t pagePoolSize()
Definition: PagePool.cpp:50
static unsigned getTID()
Definition: ThreadPool.h:204
void pagePoolFree(void *)
Definition: PagePool.cpp:48
Definition: PerThreadStorage.h:88
Unordered collection of elements.
Definition: Bag.h:42
std::enable_if_t<!std::is_scalar< internal::Val_ty< I > >::value > uninitialized_destroy(I first, I last)
Destroy a range.
Definition: gstl.h:284
bool empty() const
Definition: Bag.h:250
Main scalable allocator in Galois.
Definition: runtime/Mem.h:642
const_iterator end() const
Definition: Bag.h:241
const T * const_pointer
Definition: Bag.h:231
void swap(InsertBag &o)
Definition: Bag.h:224
unsigned size() const
Definition: PerThreadStorage.h:159
void * pagePoolAlloc()
Low level page pool (individual pages, use largeMalloc for large blocks)
Definition: PagePool.cpp:41
InsertBag()
Definition: Bag.h:203
InsertBag & operator=(InsertBag &&o)
Definition: Bag.h:209
reference push_back(ItemTy &&val)
Thread safe bag insertion.
Definition: Bag.h:298
void * allocate(size_t size)
Definition: runtime/Mem.h:655
void clear()
Definition: Bag.h:220
T * getRemote(unsigned int thread)
Definition: PerThreadStorage.h:149
Iterator(galois::substrate::PerThreadStorage< std::pair< header *, header * >> *h, unsigned t)
Definition: Bag.h:116
Iterator< T > iterator
Definition: Bag.h:234
local_iterator local_end()
Definition: Bag.h:246
T value_type
Definition: Bag.h:229
void pop()
Pop the last element pushed by this thread.
Definition: Bag.h:281
T * pointer
Definition: Bag.h:230
Definition: Bag.h:55
void deallocate(void *ptr)
Definition: runtime/Mem.h:664