00001
00026 #ifndef GALOIS_BAG_H
00027 #define GALOIS_BAG_H
00028
00029 #include "Galois/config.h"
00030 #include "Galois/gstl.h"
00031 #include "Galois/Runtime/PerThreadStorage.h"
00032 #include "Galois/Runtime/ll/gio.h"
00033 #include "Galois/Runtime/mm/Mem.h"
00034
00035 #include <boost/iterator/iterator_facade.hpp>
00036
00037 #include GALOIS_CXX11_STD_HEADER(algorithm)
00038
00039 namespace Galois {
00040
00046 template<typename T, unsigned int BlockSize = 0>
00047 class InsertBag: private boost::noncopyable {
00048
00049 struct header {
00050 header* next;
00051 T* dbegin;
00052 T* dend;
00053 T* dlast;
00054 };
00055
00056 public:
00057 template<typename U>
00058 class Iterator: public boost::iterator_facade<Iterator<U>, U, boost::forward_traversal_tag> {
00059 friend class boost::iterator_core_access;
00060
00061 Galois::Runtime::PerThreadStorage<std::pair<header*,header*> >* hd;
00062 unsigned int thr;
00063 header* p;
00064 U* v;
00065
00066 bool init_thread() {
00067 p = thr < hd->size() ? hd->getRemote(thr)->first : 0;
00068 v = p ? p->dbegin : 0;
00069 return p;
00070 }
00071
00072 bool advance_local() {
00073 if (p) {
00074 ++v;
00075 return v != p->dend;
00076 }
00077 return false;
00078 }
00079
00080 bool advance_chunk() {
00081 if (p) {
00082 p = p->next;
00083 v = p ? p->dbegin : 0;
00084 }
00085 return p;
00086 }
00087
00088 void advance_thread() {
00089 while (thr < hd->size()) {
00090 ++thr;
00091 if (init_thread())
00092 return;
00093 }
00094 }
00095
00096 void increment() {
00097 if (advance_local()) return;
00098 if (advance_chunk()) return;
00099 advance_thread();
00100 }
00101
00102 template<typename OtherTy>
00103 bool equal(const Iterator<OtherTy>& o) const {
00104 return hd == o.hd && thr == o.thr && p == o.p && v == o.v;
00105 }
00106
00107 U& dereference() const { return *v; }
00108
00109 public:
00110 Iterator(): hd(0), thr(0), p(0), v(0) { }
00111
00112 template<typename OtherTy>
00113 Iterator(const Iterator<OtherTy>& o): hd(o.hd), thr(o.thr), p(o.p), v(o.v) { }
00114
00115 Iterator(Galois::Runtime::PerThreadStorage<std::pair<header*,header*> >* h, unsigned t):
00116 hd(h), thr(t), p(0), v(0)
00117 {
00118
00119 if (!init_thread())
00120 advance_thread();
00121 }
00122 };
00123
00124 private:
00125 Galois::Runtime::MM::FixedSizeAllocator heap;
00126 Galois::Runtime::PerThreadStorage<std::pair<header*,header*> > heads;
00127
00128 void insHeader(header* h) {
00129 std::pair<header*,header*>& H = *heads.getLocal();
00130 if (H.second) {
00131 H.second->next = h;
00132 H.second = h;
00133 } else {
00134 H.first = H.second = h;
00135 }
00136 }
00137
00138 header* newHeaderFromAllocator(void *m, unsigned size) {
00139 header* H = new (m) header();
00140 int offset = 1;
00141 if (sizeof(T) < sizeof(header))
00142 offset += sizeof(header)/sizeof(T);
00143 T* a = reinterpret_cast<T*>(m);
00144 H->dbegin = &a[offset];
00145 H->dend = H->dbegin;
00146 H->dlast = &a[(size / sizeof(T))];
00147 H->next = 0;
00148 return H;
00149 }
00150
00151 header* newHeader() {
00152 if (BlockSize) {
00153 return newHeaderFromAllocator(heap.allocate(BlockSize), BlockSize);
00154 } else {
00155 return newHeaderFromAllocator(Galois::Runtime::MM::pageAlloc(), Galois::Runtime::MM::pageSize);
00156 }
00157 }
00158
00159 void destruct() {
00160 for (unsigned x = 0; x < heads.size(); ++x) {
00161 std::pair<header*,header*>& hpair = *heads.getRemote(x);
00162 header*& h = hpair.first;
00163 while (h) {
00164 uninitialized_destroy(h->dbegin, h->dend);
00165 header* h2 = h;
00166 h = h->next;
00167 if (BlockSize)
00168 heap.deallocate(h2);
00169 else
00170 Galois::Runtime::MM::pageFree(h2);
00171 }
00172 hpair.second = 0;
00173 }
00174 }
00175
00176 public:
00177
00178
00179
00180 InsertBag(): heap(BlockSize) { }
00181
00182 ~InsertBag() {
00183 destruct();
00184 }
00185
00186 void clear() {
00187 destruct();
00188 }
00189
00190 typedef T value_type;
00191 typedef const T& const_reference;
00192 typedef T& reference;
00193 typedef Iterator<T> iterator;
00194 typedef Iterator<const T> const_iterator;
00195 typedef iterator local_iterator;
00196
00197 iterator begin() { return iterator(&heads, 0); }
00198 iterator end() { return iterator(&heads, heads.size()); }
00199 const_iterator begin() const { return const_iterator(&heads, 0); }
00200 const_iterator end() const { return const_iterator(&heads, heads.size()); }
00201
00202 local_iterator local_begin() { return local_iterator(&heads, Galois::Runtime::LL::getTID()); }
00203 local_iterator local_end() { return local_iterator(&heads, Galois::Runtime::LL::getTID() + 1); }
00204
00205 bool empty() const {
00206 for (unsigned x = 0; x < heads.size(); ++x) {
00207 header* h = heads.getRemote(x)->first;
00208 if (h)
00209 return false;
00210 }
00211 return true;
00212 }
00213
00215 template<typename... Args>
00216 reference emplace(Args&&... args) {
00217 header* H = heads.getLocal()->second;
00218 T* rv;
00219 if (!H || H->dend == H->dlast) {
00220 H = newHeader();
00221 insHeader(H);
00222 }
00223 rv = new (H->dend) T(std::forward<Args>(args)...);
00224 H->dend++;
00225 return *rv;
00226 }
00227
00229 reference push(const T& val) { return emplace(val); }
00231 reference push(T&& val) { return emplace(std::move(val)); }
00232
00234 reference push_back(const T& val) { return emplace(val); }
00236 reference push_back(T&& val) { return emplace(std::move(val)); }
00237 };
00238
00239 }
00240
00241 #endif