00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00023
00024 #ifndef BTK_UTILITY_GROUPED_ELEMENT_ITERATOR_HPP
00025 #define BTK_UTILITY_GROUPED_ELEMENT_ITERATOR_HPP
00026
00027 #include <boost/type_traits/is_convertible.hpp>
00028 #include <boost/utility/enable_if.hpp>
00029 #include <boost/iterator/iterator_facade.hpp>
00030
00031 #include <btk/core/common/debugging.hpp>
00032 #include <btk/core/common/assertions.hpp>
00033
00034 namespace BTK {
00035 namespace UTILITY {
00036
00051 template <typename GroupIterator,
00052 typename ElementIterator,
00053 typename GroupType,
00054 typename ElementType>
00055 class GroupedElementIterator : public
00056 boost::iterator_facade<GroupedElementIterator<GroupIterator,
00057 ElementIterator,
00058 GroupType,
00059 ElementType>,
00060 ElementType, boost::bidirectional_traversal_tag>
00061 {
00062
00063 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00064
00065
00066
00067
00068 template <typename A, typename B, typename C, typename D>
00069 friend class GroupedElementIterator;
00070
00071
00072
00073
00074
00075
00076
00077
00078 template <class Ret, class T>
00079 class dc_mem_fun_ref
00080 {
00081 typedef Ret (T::*func_ptr)();
00082
00083 public:
00084 dc_mem_fun_ref() : func(static_cast<func_ptr>(0)) {}
00085 explicit dc_mem_fun_ref(func_ptr fp) : func(fp) {}
00086 Ret operator()(T & r) const
00087 {
00088
00089
00090 BTK_ASSERT(func != static_cast<func_ptr>(0),
00091 "Null ptr dereference in GroupedElementIterator::def_cons_mem_fun_ref");
00092 return (r.*func)();
00093 }
00094
00095 private:
00096 func_ptr func;
00097 };
00098 #endif // DOXYGEN_SHOULD_SKIP_THIS
00099
00100 public:
00101
00109 GroupedElementIterator()
00110 {
00111
00112
00113
00114 _cur_group = _group_container_end = _group_container_begin;
00115 _cur_element = _group_begin = _group_end;
00116 }
00117
00119
00120 GroupedElementIterator(GroupIterator begin,
00121 GroupIterator end,
00122 ElementIterator (GroupType::*group_begin_fun) (),
00123 ElementIterator (GroupType::*group_end_fun) (),
00124 bool at_end = false) :
00125 _cur_group(begin), _group_container_begin(begin), _group_container_end(end),
00126 _cur_element(), _group_begin(), _group_end(),
00127 _group_begin_fun(group_begin_fun),
00128 _group_end_fun(group_end_fun)
00129 {
00130 initialize(begin,end,at_end);
00131 }
00132
00133 GroupedElementIterator(GroupIterator begin,
00134 GroupIterator end,
00135 bool at_end = false) :
00136 _cur_group(begin), _group_container_begin(begin), _group_container_end(end),
00137 _cur_element(), _group_begin(), _group_end(),
00138 _group_begin_fun(&GroupType::begin),
00139 _group_end_fun(&GroupType::end)
00140 {
00141 initialize(begin,end,at_end);
00142 }
00144
00162 template <typename GI, typename EI, typename GT, typename ET>
00163 GroupedElementIterator(GroupedElementIterator<GI,EI,GT,ET> const & other,
00164 ElementIterator (GroupType::*group_begin_fun) () =
00165 &GroupType::begin,
00166 ElementIterator (GroupType::*group_end_fun) () =
00167 &GroupType::end,
00168 typename boost::enable_if<
00169 boost::is_convertible<GI,GroupIterator>
00170 >::type * d1 = 0,
00171 typename boost::enable_if<
00172 boost::is_convertible<EI,ElementIterator>
00173 >::type * d2 = 0,
00174 typename boost::enable_if<
00175 boost::is_convertible<GT,GroupType>
00176 >::type * d3 = 0,
00177 typename boost::enable_if<
00178 boost::is_convertible<ET,ElementType>
00179 >::type * d4 = 0) :
00180 _cur_group(other._cur_group),
00181 _group_container_begin(other._group_container_begin),
00182 _group_container_end(other._group_container_end),
00183 _cur_element(other._cur_element),
00184 _group_begin(other._group_begin),
00185 _group_end(other._group_end),
00186 _group_begin_fun(group_begin_fun),
00187 _group_end_fun(group_end_fun) {}
00188
00189 friend std::ostream & operator<<(std::ostream & os,
00190 GroupedElementIterator<GroupIterator,
00191 ElementIterator,
00192 GroupType,
00193 ElementType> const & gei)
00194 {
00195 os << "GroupedElementIterator: " << std::endl
00196 << " _cur_element: " << &*gei._cur_element << std::endl
00197 << " _group_begin: " << &*gei._group_begin << std::endl
00198 << " _group_end: " << &*gei._group_end << std::endl
00199 << " _cur_group: " << &*gei._cur_group << std::endl
00200 << " _group_container_begin: " << &*gei._group_container_begin << std::endl
00201 << " _group_container_end: " << &*gei._group_container_end << std::endl;
00202
00203 return os;
00204 }
00205
00206 private:
00207 friend class boost::iterator_core_access;
00208
00209 void initialize(GroupIterator begin,
00210 GroupIterator end,
00211 bool at_end)
00212 {
00213 BTK_ASSERT((begin != end),
00214 "Attempt to create GroupedElementIterator from 0-element range!");
00215
00216 if (at_end) {
00217
00218
00219 _cur_group = end;
00220 --_cur_group;
00221 _group_begin = _group_begin_fun(*_cur_group);
00222 _group_end = _group_end_fun(*_cur_group);
00223 _cur_element = _group_end;
00224
00225
00226 _cur_group = end;
00227 } else {
00228 _cur_element = _group_begin_fun(*_cur_group);
00229 _group_begin = _cur_element;
00230 _group_end = _group_end_fun(*_cur_group);
00231
00232
00233
00234
00235
00236 if (_group_begin == _group_end) increment();
00237 }
00238 }
00239
00240 void increment()
00241 {
00242 TRACE_OUT << "In GroupedElementIterator::increment():" << std::endl;
00243
00244
00245 if (_cur_element == _group_end || ++_cur_element == _group_end) {
00246
00247
00248 TRACE_OUT << " Advanced one element ("
00249 << "_cur_element=" << &*_cur_element
00250 << ", _group_end=" << &*_group_end
00251 << ")" << std::endl;
00252
00253 if (_cur_group != _group_container_end &&
00254 ++_cur_group != _group_container_end) {
00255
00256 _group_begin = _group_begin_fun(*_cur_group);
00257 _group_end = _group_end_fun(*_cur_group);
00258 _cur_element = _group_begin;
00259
00260 TRACE_OUT << " Advanced one group ("
00261 << "_cur_group=" << &*_cur_group
00262 << ", _group_begin=" << &*_group_begin
00263 << ", _group_end=" << &*_group_end
00264 << ")" << std::endl;
00265
00266
00267 if (_group_begin == _group_end) {
00268 TRACE_OUT << " New group is empty! Re-calling increment()..." << std::endl;
00269 increment();
00270 }
00271 } else {
00272
00273 _cur_group = _group_container_end;
00274 _cur_element = _group_end;
00275
00276 TRACE_OUT << " Can't move forward -- at last group ("
00277 << "_cur_group=" << &*_cur_group
00278 << ", _group_end=" << &*_group_end
00279 << ")" << std::endl;
00280 }
00281 }
00282 }
00283
00284 void decrement()
00285 {
00286 TRACE_OUT << "In GroupedElementIterator::decrement():" << std::endl;
00287
00288 if (_cur_element == _group_begin) {
00289
00290 TRACE_OUT << " At group beginning ("
00291 << "_cur_element=_group_begin="
00292 << &*_group_begin
00293 << ", _cur_group=" << &*_cur_group
00294 << ")" << std::endl;
00295
00296 if (_cur_group != _group_container_begin) {
00297
00298 --_cur_group;
00299 _group_begin = _group_begin_fun(*_cur_group);
00300 _group_end = _group_end_fun(*_cur_group);
00301
00302 TRACE_OUT << " Moved one group back ("
00303 << "_cur_group=" << &*_cur_group
00304 << ", _group_begin=" << &*_group_begin
00305 << ", _group_end=" << &*_group_end
00306 << ")" << std::endl;
00307
00308
00309 if (_group_begin == _group_end) {
00310 TRACE_OUT << " New group is empty! Re-calling deccrement()..." << std::endl;
00311 decrement();
00312 } else {
00313
00314 _cur_element = --(_group_end_fun(*_cur_group));
00315 }
00316 } else {
00317
00318 _cur_group = _group_container_begin;
00319 _cur_element = _group_begin;
00320
00321 TRACE_OUT << " Can't move back -- at first group ("
00322 << "_cur_group=" << &*_cur_group
00323 << ", _group_begin=" << &*_group_begin
00324 << ")" << std::endl;
00325 }
00326 } else {
00327
00328 --_cur_element;
00329
00330
00331
00332 if (_cur_group == _group_container_end) --_cur_group;
00333
00334 TRACE_OUT << " Moved back one element ("
00335 << "_cur_element=" << &*_cur_element
00336 << ", _group_begin=" << &*_group_begin
00337 << ", _cur_group=" << &*_cur_group
00338 << ")" << std::endl;
00339 }
00340 }
00341
00342 ElementType & dereference() const
00343 {
00344 return *_cur_element;
00345 }
00346
00347
00348 template <typename GI, typename EI, typename GT, typename ET>
00349 bool equal(GroupedElementIterator<GI,EI,GT,ET> const & rhs) const
00350 {
00351 TRACE_OUT << "In GroupedElementIterator::equal():" << std::endl
00352 << " _cur_element: LHS=" << &*_cur_element
00353 << ", RHS=" << &*rhs._cur_element << std::endl
00354 << " _cur_group: LHS=" << &*_cur_group
00355 << ", RHS=" << &*rhs._cur_group << std::endl;
00356
00357
00358
00359 if (_cur_element == rhs._cur_element &&
00360 _cur_group == rhs._cur_group) return true;
00361
00362 TRACE_OUT << " NOT equal." << std::endl;
00363
00364 return false;
00365 }
00366
00367 GroupIterator _cur_group;
00368 GroupIterator _group_container_begin;
00369 GroupIterator _group_container_end;
00370
00371 ElementIterator _cur_element;
00372 ElementIterator _group_begin;
00373 ElementIterator _group_end;
00374
00375 dc_mem_fun_ref<ElementIterator,GroupType> _group_begin_fun;
00376 dc_mem_fun_ref<ElementIterator,GroupType> _group_end_fun;
00377 };
00378
00379 }
00380 }
00381
00382 #endif