00001
00027 #ifndef GALOIS_TWOLEVELITERATORA_H
00028 #define GALOIS_TWOLEVELITERATORA_H
00029
00030 #include "Galois/config.h"
00031 #include "Galois/Runtime/ll/gio.h"
00032
00033 #include <boost/iterator/iterator_adaptor.hpp>
00034 #include <cassert>
00035 #include <iterator>
00036 #include GALOIS_CXX11_STD_HEADER(type_traits)
00037 #include GALOIS_CXX11_STD_HEADER(utility)
00038
00039 namespace Galois {
00040
00044 template<class OuterIter, class InnerIter, class CategoryOrTraversal, class InnerBeginFn, class InnerEndFn>
00045 class TwoLevelIteratorA :
00046 public boost::iterator_adaptor<
00047 TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>,
00048 InnerIter,
00049 boost::use_default,
00050 CategoryOrTraversal
00051 >
00052 {
00053 public:
00054 typedef typename TwoLevelIteratorA::iterator_adaptor_::difference_type difference_type;
00055
00056 private:
00057 OuterIter m_outer_begin;
00058 OuterIter m_outer_end;
00059 OuterIter m_outer;
00060 InnerBeginFn m_inner_begin_fn;
00061 InnerEndFn m_inner_end_fn;
00062
00063 #if __cplusplus >= 201103L
00064 static_assert(std::is_convertible<InnerIter,
00065 typename std::result_of<InnerBeginFn(decltype(*std::declval<OuterIter>()))>::type>::value,
00066 "InnerIter should be convertable to result of InnerBeginFn(*OuterIter)");
00067 static_assert(std::is_convertible<InnerIter,
00068 typename std::result_of<InnerEndFn(decltype(*std::declval<OuterIter>()))>::type>::value,
00069 "InnerIter should be convertable to result of InnerEndFn(*OuterIter)");
00070 #endif
00071
00072 friend class boost::iterator_core_access;
00073
00078 void seek_forward() {
00079 if (this->base_reference() != m_inner_end_fn(*m_outer))
00080 return;
00081
00082 ++m_outer;
00083
00084 for (; m_outer != m_outer_end; ++m_outer) {
00085 this->base_reference() = m_inner_begin_fn(*m_outer);
00086
00087 if (this->base_reference() != m_inner_end_fn(*m_outer))
00088 break;
00089 }
00090 }
00091
00092 template<class Iter>
00093 void safe_decrement_dispatch(std::forward_iterator_tag, Iter& it, Iter begin) {
00094 Iter prev = begin;
00095
00096 for (; begin != it; ++begin)
00097 prev = begin;
00098
00099 return prev;
00100 }
00101
00102 template<class Iter>
00103 void safe_decrement_dispatch(std::bidirectional_iterator_tag, Iter& it, const Iter& begin) { --it; }
00104
00106 template<class Iter>
00107 bool safe_decrement(Iter& it, const Iter& begin) {
00108 if (it == begin)
00109 return true;
00110 safe_decrement_dispatch(typename std::iterator_traits<Iter>::iterator_category(), it, begin);
00111 return false;
00112 }
00113
00114 template<class Iter>
00115 typename std::iterator_traits<Iter>::difference_type
00116 safe_difference_dispatch(Iter it1, Iter it2, Iter end, std::input_iterator_tag) const {
00117 if (it1 == it2)
00118 return 0;
00119
00120 Iter it1_orig(it1);
00121 Iter it2_orig(it2);
00122
00123 typename std::iterator_traits<Iter>::difference_type count1 = 0;
00124 typename std::iterator_traits<Iter>::difference_type count2 = 0;
00125
00126 while (true) {
00127 if (it1 != end) {
00128 ++count1;
00129 if (++it1 == it2_orig)
00130 return count1;
00131 }
00132 if (it2 != end) {
00133 ++count2;
00134 if (++it2 == it1_orig)
00135 return -count2;
00136 }
00137 }
00138 }
00139
00140 template<class Iter>
00141 typename std::iterator_traits<Iter>::difference_type
00142 safe_difference_dispatch(Iter it1, Iter it2, Iter end, std::random_access_iterator_tag) const {
00143 return std::distance(it1, it2);
00144 }
00145
00150 template<class Iter>
00151 typename std::iterator_traits<Iter>::difference_type
00152 safe_distance(Iter it1, Iter it2, Iter end) const {
00153 return safe_difference_dispatch(it1, it2, end, typename std::iterator_traits<Iter>::iterator_category());
00154 }
00155
00160 void seek_backward() {
00161 InnerIter end;
00162
00163 for (end = m_inner_end_fn(*m_outer); m_inner_begin_fn(*m_outer) == end; ) {
00164 bool too_far = safe_decrement(m_outer, m_outer_begin);
00165 assert(!too_far);
00166 end = m_inner_end_fn(*m_outer);
00167 }
00168
00169 this->base_reference() = end;
00170 }
00171
00172 void increment() {
00173 ++this->base_reference();
00174 seek_forward();
00175 }
00176
00177 void decrement() {
00178 if (m_outer == m_outer_end) {
00179 bool too_far = safe_decrement(m_outer, m_outer_begin);
00180 assert(!too_far);
00181 seek_backward();
00182 } else if (!safe_decrement(this->base_reference(), m_inner_begin_fn(*m_outer))) {
00183
00184 return;
00185 } else {
00186
00187 bool too_far = safe_decrement(m_outer, m_outer_begin);
00188 assert(!too_far);
00189 seek_backward();
00190 }
00191
00192 bool too_far = safe_decrement(this->base_reference(), m_inner_begin_fn(*m_outer));
00193 assert(!too_far);
00194 }
00195
00196 template<class DiffType = difference_type>
00197 void advance_dispatch(DiffType n, std::input_iterator_tag) {
00198 if (n < 0) {
00199 for (; n; ++n)
00200 decrement();
00201 } else if (n > 0) {
00202 for (; n; --n)
00203 increment();
00204 }
00205 }
00206
00207 template<class DiffType = difference_type>
00208 void jump_forward(DiffType n) {
00209 while (n) {
00210 difference_type k = std::distance(this->base_reference(), m_inner_end_fn(*m_outer));
00211 difference_type s = std::min(k, n);
00212 n -= s;
00213 std::advance(this->base_reference(), s);
00214 if (s == k)
00215 seek_forward();
00216 }
00217 }
00218
00219 template<class DiffType = difference_type>
00220 void jump_backward(DiffType n) {
00221
00222
00223 if (n && m_outer == m_outer_end) {
00224 decrement();
00225 --n;
00226 }
00227
00228 while (n) {
00229 difference_type k = std::distance(m_inner_begin_fn(*m_outer), this->base_reference());
00230 if (k == 0) {
00231 decrement();
00232 --n;
00233 } else if (k <= n) {
00234 std::advance(this->base_reference(), -n);
00235 n = 0;
00236 } else {
00237 seek_backward();
00238 n -= k;
00239 }
00240 }
00241 }
00242
00243 template<class DiffType = difference_type>
00244 void advance_dispatch(DiffType n, std::random_access_iterator_tag) {
00245 if (n < 0) {
00246 jump_backward(-n);
00247 } else if (n > 0) {
00248 jump_forward(n);
00249 }
00250 }
00251
00252 void advance(difference_type n) {
00253 advance_dispatch(n, typename std::iterator_traits<InnerIter>::iterator_category());
00254 }
00255
00256 template<class Other>
00257 difference_type distance_to_dispatch(Other it2, std::input_iterator_tag) const {
00258
00259
00260 if (*this == it2)
00261 return 0;
00262
00263 TwoLevelIteratorA it1(*this);
00264 TwoLevelIteratorA it2_orig(it2);
00265
00266 difference_type count1 = 0;
00267 difference_type count2 = 0;
00268
00269 while (true) {
00270 if (it1.m_outer != it1.m_outer_end) {
00271 ++count1;
00272 if (++it1 == it2_orig)
00273 return count1;
00274 }
00275 if (it2.m_outer != it2.m_outer_end) {
00276 ++count2;
00277 if (++it2 == *this)
00278 return -count2;
00279 }
00280 }
00281 }
00282
00283 template<class Other>
00284 difference_type distance_to_dispatch(const Other& x, std::random_access_iterator_tag) const {
00285 if (*this == x)
00286 return 0;
00287 else if (m_outer == x.m_outer)
00288 return safe_distance(this->base_reference(), x.base_reference(), m_inner_end_fn(*m_outer));
00289 else if (safe_distance(m_outer, x.m_outer, m_outer_end) < 0)
00290 return -x.distance_to(*this);
00291
00292 difference_type me_count = 0;
00293
00294 TwoLevelIteratorA me(*this);
00295
00296 while (me.m_outer != me.m_outer_end) {
00297 difference_type d;
00298 if (me.m_outer != x.m_outer)
00299 d = std::distance(me.base_reference(), me.m_inner_end_fn(*me.m_outer));
00300 else
00301 d = std::distance(me.base_reference(), x.base_reference());
00302 me_count += d;
00303 std::advance(me, d);
00304 if (me == x)
00305 return me_count;
00306 }
00307
00308 GALOIS_DIE("invalid iterator ", std::distance(m_outer, x.m_outer));
00309 return 0;
00310 }
00311
00312 template<class OtherOuterIter, class OtherInnerIter, class C, class BF, class EF>
00313 difference_type distance_to(const TwoLevelIteratorA<OtherOuterIter, OtherInnerIter, C, BF, EF>& x) const {
00314 return distance_to_dispatch(x, typename std::iterator_traits<InnerIter>::iterator_category());
00315 }
00316
00317 template<class OtherOuterIter, class OtherInnerIter, class C, class BF, class EF>
00318 bool equal(const TwoLevelIteratorA<OtherOuterIter, OtherInnerIter, C, BF, EF>& x) const {
00319
00320 if (m_outer == m_outer_end && m_outer == x.m_outer)
00321 return true;
00322
00323 return this->base_reference() == x.base_reference() && m_outer == x.m_outer;
00324 }
00325
00326 public:
00327 TwoLevelIteratorA() { }
00328
00329 TwoLevelIteratorA(
00330 OuterIter outer_begin,
00331 OuterIter outer_end,
00332 OuterIter outer,
00333 InnerBeginFn inner_begin_fn,
00334 InnerEndFn inner_end_fn):
00335 m_outer_begin(outer_begin),
00336 m_outer_end(outer_end),
00337 m_outer(outer),
00338 m_inner_begin_fn(inner_begin_fn),
00339 m_inner_end_fn(inner_end_fn)
00340 {
00341 if (m_outer != m_outer_end) {
00342 this->base_reference() = m_inner_begin_fn(*m_outer);
00343 seek_forward();
00344 }
00345 }
00346 };
00347
00349 struct GetBegin {
00350 template<class T>
00351 auto operator()(T&& x) const -> decltype(std::forward<T>(x).begin()) { return std::forward<T>(x).begin(); }
00352 };
00353
00355 struct GetEnd {
00356 template<class T>
00357 auto operator()(T&& x) const -> decltype(std::forward<T>(x).end()) { return std::forward<T>(x).end(); }
00358 };
00359
00360 #if __cplusplus >= 201103L
00361 template<
00362 class CategoryOrTraversal = std::forward_iterator_tag,
00363 class OuterIter,
00364 class InnerIter = decltype(std::declval<OuterIter>()->begin()),
00365 class InnerBeginFn = GetBegin,
00366 class InnerEndFn = GetEnd,
00367 class Iter = TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>
00368 >
00369 std::pair<Iter,Iter>
00370 make_two_level_iterator(OuterIter outer_begin, OuterIter outer_end)
00371 {
00372 return std::make_pair(
00373 Iter(outer_begin, outer_end, outer_begin, InnerBeginFn(), InnerEndFn()),
00374 Iter(outer_begin, outer_end, outer_end, InnerBeginFn(), InnerEndFn()));
00375 }
00376 #else
00377
00378 template<
00379 class CategoryOrTraversal,
00380 class OuterIter,
00381 class InnerIter,
00382 class InnerBeginFn,
00383 class InnerEndFn
00384 >
00385 std::pair<
00386 TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>,
00387 TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>
00388 >
00389 make_two_level_iterator(OuterIter outer_begin, OuterIter outer_end)
00390 {
00391 return std::make_pair(
00392 TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>
00393 (outer_begin, outer_end, outer_begin, InnerBeginFn(), InnerEndFn()),
00394 TwoLevelIteratorA<OuterIter, InnerIter, CategoryOrTraversal, InnerBeginFn, InnerEndFn>
00395 (outer_begin, outer_end, outer_end, InnerBeginFn(), InnerEndFn()));
00396 }
00397 #endif
00398
00399 }
00400
00401 #endif