/indra/llcommon/lltreeiterators.h

https://bitbucket.org/lindenlab/viewer-beta/ · C++ Header · 705 lines · 349 code · 41 blank · 315 comment · 17 complexity · 80f9db743681f3e800844d6de6d1fce7 MD5 · raw file

  1. /**
  2. * @file lltreeiterators.h
  3. * @author Nat Goodspeed
  4. * @date 2008-08-19
  5. * @brief This file defines iterators useful for traversing arbitrary node
  6. * classes, potentially polymorphic, linked into strict tree
  7. * structures.
  8. *
  9. * Dereferencing any one of these iterators actually yields a @em
  10. * pointer to the node in question. For example, given an
  11. * LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
  12. * to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
  13. * More commonly, instead of writing <tt>li->member</tt>, you write
  14. * <tt>(*li)->member</tt> -- as you would if you were traversing an
  15. * STL container of MyNode pointers.
  16. *
  17. * It would certainly be possible to build these iterators so that
  18. * <tt>*iterator</tt> would return a reference to the node itself
  19. * rather than a pointer to the node, and for many purposes it would
  20. * even be more convenient. However, that would be insufficiently
  21. * flexible. If you want to use an iterator range to (e.g.) initialize
  22. * a std::vector collecting results -- you rarely want to actually @em
  23. * copy the nodes in question. You're much more likely to want to copy
  24. * <i>pointers to</i> the traversed nodes. Hence these iterators
  25. * produce pointers.
  26. *
  27. * Though you specify the actual NODE class as the template parameter,
  28. * these iterators internally use LLPtrTo<> to discover whether to
  29. * store and return an LLPointer<NODE> or a simple NODE*.
  30. *
  31. * By strict tree structures, we mean that each child must have
  32. * exactly one parent. This forbids a child claiming any ancestor as a
  33. * child of its own. Child nodes with multiple parents will be visited
  34. * once for each parent. Cycles in the graph will result in either an
  35. * infinite loop or an out-of-memory crash. You Have Been Warned.
  36. *
  37. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  38. * Second Life Viewer Source Code
  39. * Copyright (C) 2010, Linden Research, Inc.
  40. *
  41. * This library is free software; you can redistribute it and/or
  42. * modify it under the terms of the GNU Lesser General Public
  43. * License as published by the Free Software Foundation;
  44. * version 2.1 of the License only.
  45. *
  46. * This library is distributed in the hope that it will be useful,
  47. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  48. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  49. * Lesser General Public License for more details.
  50. *
  51. * You should have received a copy of the GNU Lesser General Public
  52. * License along with this library; if not, write to the Free Software
  53. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  54. *
  55. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  56. * $/LicenseInfo$
  57. */
  58. #if ! defined(LL_LLTREEITERATORS_H)
  59. #define LL_LLTREEITERATORS_H
  60. #include "llptrto.h"
  61. #include <vector>
  62. #include <deque>
  63. #include <boost/iterator/iterator_facade.hpp>
  64. #include <boost/function.hpp>
  65. #include <boost/static_assert.hpp>
  66. namespace LLTreeIter
  67. {
  68. /// Discriminator between LLTreeUpIter and LLTreeDownIter
  69. enum RootIter { UP, DOWN };
  70. /// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
  71. enum WalkIter { DFS_PRE, DFS_POST, BFS };
  72. }
  73. /**
  74. * LLBaseIter defines some machinery common to all these iterators. We use
  75. * boost::iterator_facade to define the iterator boilerplate: the conventional
  76. * operators and methods necessary to implement a standards-conforming
  77. * iterator. That allows us to specify the actual iterator semantics in terms
  78. * of equal(), dereference() and increment() methods.
  79. */
  80. template <class SELFTYPE, class NODE>
  81. class LLBaseIter: public boost::iterator_facade<SELFTYPE,
  82. // use pointer type as the
  83. // reference type
  84. typename LLPtrTo<NODE>::type,
  85. boost::forward_traversal_tag>
  86. {
  87. protected:
  88. /// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
  89. typedef typename LLPtrTo<NODE>::type ptr_type;
  90. /// function that advances from this node to next accepts a node pointer
  91. /// and returns another
  92. typedef boost::function<ptr_type(const ptr_type&)> func_type;
  93. typedef SELFTYPE self_type;
  94. };
  95. /// Functor returning NULL, suitable for an end-iterator's 'next' functor
  96. template <class NODE>
  97. typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
  98. {
  99. return typename LLPtrTo<NODE>::type();
  100. }
  101. /**
  102. * LLLinkedIter is an iterator over an intrusive singly-linked list. The
  103. * beginning of the list is represented by LLLinkedIter(list head); the end is
  104. * represented by LLLinkedIter().
  105. *
  106. * The begin LLLinkedIter must be instantiated with a functor to extract the
  107. * 'next' pointer from the current node. Supposing that the link pointer is @c
  108. * public, something like:
  109. *
  110. * @code
  111. * NODE* mNext;
  112. * @endcode
  113. *
  114. * you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
  115. * Alternatively, you can bind whatever accessor method is normally used to
  116. * advance to the next node, e.g. for:
  117. *
  118. * @code
  119. * NODE* next() const;
  120. * @endcode
  121. *
  122. * you can use <tt>boost::bind(&NODE::next, _1)</tt>.
  123. */
  124. template <class NODE>
  125. class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
  126. {
  127. typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
  128. protected:
  129. /// some methods need to return a reference to self
  130. typedef typename super::self_type self_type;
  131. typedef typename super::ptr_type ptr_type;
  132. typedef typename super::func_type func_type;
  133. public:
  134. /// Instantiate an LLLinkedIter to start a range, or to end a range before
  135. /// a particular list entry. Pass a functor to extract the 'next' pointer
  136. /// from the current node.
  137. LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
  138. mCurrent(entry),
  139. mNextFunc(nextfunc)
  140. {}
  141. /// Instantiate an LLLinkedIter to end a range at the end of the list
  142. LLLinkedIter():
  143. mCurrent(),
  144. mNextFunc(LLNullNextFunctor<NODE>)
  145. {}
  146. private:
  147. /// leverage boost::iterator_facade
  148. friend class boost::iterator_core_access;
  149. /// advance
  150. void increment()
  151. {
  152. mCurrent = mNextFunc(mCurrent);
  153. }
  154. /// equality
  155. bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
  156. /// dereference
  157. ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
  158. ptr_type mCurrent;
  159. func_type mNextFunc;
  160. };
  161. /**
  162. * LLTreeUpIter walks from the node in hand to the root of the tree. The term
  163. * "up" is applied to a tree visualized with the root at the top.
  164. *
  165. * LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
  166. * can navigate that way at all contains parent pointers.
  167. */
  168. template <class NODE>
  169. class LLTreeUpIter: public LLLinkedIter<NODE>
  170. {
  171. typedef LLLinkedIter<NODE> super;
  172. public:
  173. /// Instantiate an LLTreeUpIter to start from a particular tree node, or
  174. /// to end a parent traversal before reaching a particular ancestor. Pass
  175. /// a functor to extract the 'parent' pointer from the current node.
  176. LLTreeUpIter(const typename super::ptr_type& node,
  177. const typename super::func_type& parentfunc):
  178. super(node, parentfunc)
  179. {}
  180. /// Instantiate an LLTreeUpIter to end a range at the root of the tree
  181. LLTreeUpIter():
  182. super()
  183. {}
  184. };
  185. /**
  186. * LLTreeDownIter walks from the root of the tree to the node in hand. The
  187. * term "down" is applied to a tree visualized with the root at the top.
  188. *
  189. * Though you instantiate the begin() LLTreeDownIter with a pointer to some
  190. * node at an arbitrary location in the tree, the root will be the first node
  191. * you dereference and the passed node will be the last node you dereference.
  192. *
  193. * On construction, LLTreeDownIter walks from the current node to the root,
  194. * capturing the path. Then in use, it replays that walk in reverse. As with
  195. * all traversals of interesting data structures, it is actively dangerous to
  196. * modify the tree during an LLTreeDownIter walk.
  197. */
  198. template <class NODE>
  199. class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
  200. {
  201. typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
  202. typedef typename super::self_type self_type;
  203. protected:
  204. typedef typename super::ptr_type ptr_type;
  205. typedef typename super::func_type func_type;
  206. private:
  207. typedef std::vector<ptr_type> list_type;
  208. public:
  209. /// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
  210. /// functor to extract the 'parent' pointer from the current node.
  211. LLTreeDownIter(const ptr_type& node,
  212. const func_type& parentfunc)
  213. {
  214. for (ptr_type n = node; n; n = parentfunc(n))
  215. mParents.push_back(n);
  216. }
  217. /// Instantiate an LLTreeDownIter representing "here", the end of the loop
  218. LLTreeDownIter() {}
  219. private:
  220. /// leverage boost::iterator_facade
  221. friend class boost::iterator_core_access;
  222. /// advance
  223. void increment()
  224. {
  225. mParents.pop_back();
  226. }
  227. /// equality
  228. bool equal(const self_type& that) const { return this->mParents == that.mParents; }
  229. /// implement dereference/indirection operators
  230. ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
  231. list_type mParents;
  232. };
  233. /**
  234. * When you want to select between LLTreeUpIter and LLTreeDownIter with a
  235. * compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
  236. * template arg.
  237. */
  238. template <LLTreeIter::RootIter DISCRIM, class NODE>
  239. class LLTreeRootIter
  240. {
  241. enum { use_a_valid_LLTreeIter_RootIter_value = false };
  242. public:
  243. /// Bogus constructors for default (unrecognized discriminator) case
  244. template <typename TYPE1, typename TYPE2>
  245. LLTreeRootIter(TYPE1, TYPE2)
  246. {
  247. BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
  248. }
  249. LLTreeRootIter()
  250. {
  251. BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
  252. }
  253. };
  254. /// Specialize for LLTreeIter::UP
  255. template <class NODE>
  256. class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
  257. {
  258. typedef LLTreeUpIter<NODE> super;
  259. public:
  260. /// forward begin ctor
  261. LLTreeRootIter(const typename super::ptr_type& node,
  262. const typename super::func_type& parentfunc):
  263. super(node, parentfunc)
  264. {}
  265. /// forward end ctor
  266. LLTreeRootIter():
  267. super()
  268. {}
  269. };
  270. /// Specialize for LLTreeIter::DOWN
  271. template <class NODE>
  272. class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
  273. {
  274. typedef LLTreeDownIter<NODE> super;
  275. public:
  276. /// forward begin ctor
  277. LLTreeRootIter(const typename super::ptr_type& node,
  278. const typename super::func_type& parentfunc):
  279. super(node, parentfunc)
  280. {}
  281. /// forward end ctor
  282. LLTreeRootIter():
  283. super()
  284. {}
  285. };
  286. /**
  287. * Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
  288. * a depth-first tree walk through that node and all its descendants.
  289. *
  290. * The begin() LLTreeDFSIter must be instantiated with functors to obtain from
  291. * a given node begin() and end() iterators for that node's children. For this
  292. * reason, you must specify the type of the node's child iterator as an
  293. * additional template parameter.
  294. *
  295. * Specifically, the begin functor must return an iterator whose dereferenced
  296. * value is a @em pointer to a child tree node. For instance, if each node
  297. * tracks its children in an STL container of node* pointers, you can simply
  298. * return that container's begin() iterator.
  299. *
  300. * Alternatively, if a node tracks its children with a classic linked list,
  301. * write a functor returning LLLinkedIter<NODE>.
  302. *
  303. * The end() LLTreeDFSIter must, of course, match the begin() iterator's
  304. * template parameters, but is constructed without runtime parameters.
  305. */
  306. template <class NODE, typename CHILDITER>
  307. class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
  308. {
  309. typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
  310. typedef typename super::self_type self_type;
  311. protected:
  312. typedef typename super::ptr_type ptr_type;
  313. // The func_type is different for this: from a NODE pointer, we must
  314. // obtain a CHILDITER.
  315. typedef boost::function<CHILDITER(const ptr_type&)> func_type;
  316. private:
  317. typedef std::vector<ptr_type> list_type;
  318. public:
  319. /// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
  320. /// functors to extract the 'child begin' and 'child end' iterators from
  321. /// each node.
  322. LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
  323. : mBeginFunc(beginfunc),
  324. mEndFunc(endfunc),
  325. mSkipChildren(false)
  326. {
  327. // Only push back this node if it's non-NULL!
  328. if (node)
  329. mPending.push_back(node);
  330. }
  331. /// Instantiate an LLTreeDFSIter to mark the end of the walk
  332. LLTreeDFSIter() : mSkipChildren(false) {}
  333. /// flags iterator logic to skip traversing children of current node on next increment
  334. void skipDescendants(bool skip = true) { mSkipChildren = skip; }
  335. private:
  336. /// leverage boost::iterator_facade
  337. friend class boost::iterator_core_access;
  338. /// advance
  339. /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
  340. void increment()
  341. {
  342. // Capture the node we were just looking at
  343. ptr_type current = mPending.back();
  344. // Remove it from mPending so we don't process it again later
  345. mPending.pop_back();
  346. if (!mSkipChildren)
  347. {
  348. // Add all its children to mPending
  349. addChildren(current);
  350. }
  351. // reset flag after each step
  352. mSkipChildren = false;
  353. }
  354. /// equality
  355. bool equal(const self_type& that) const { return this->mPending == that.mPending; }
  356. /// implement dereference/indirection operators
  357. ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
  358. /// Add the direct children of the specified node to mPending
  359. void addChildren(const ptr_type& node)
  360. {
  361. // If we just use push_back() for each child in turn, we'll end up
  362. // processing children in reverse order. We don't want to assume
  363. // CHILDITER is reversible: some of the linked trees we'll be
  364. // processing manage their children using singly-linked lists. So
  365. // figure out how many children there are, grow mPending by that size
  366. // and reverse-copy the children into the new space.
  367. CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
  368. // grow mPending by the number of children
  369. mPending.resize(mPending.size() + std::distance(chi, chend));
  370. // reverse-copy the children into the newly-expanded space
  371. std::copy(chi, chend, mPending.rbegin());
  372. }
  373. /// list of the nodes yet to be processed
  374. list_type mPending;
  375. /// functor to extract begin() child iterator
  376. func_type mBeginFunc;
  377. /// functor to extract end() child iterator
  378. func_type mEndFunc;
  379. /// flag which controls traversal of children (skip children of current node if true)
  380. bool mSkipChildren;
  381. };
  382. /**
  383. * Instantiated with a tree node, typically the root, LLTreeDFSPostIter
  384. * "flattens" a depth-first tree walk through that node and all its
  385. * descendants. Whereas LLTreeDFSIter visits each node before visiting any of
  386. * its children, LLTreeDFSPostIter visits all of a node's children before
  387. * visiting the node itself.
  388. *
  389. * The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
  390. * from a given node begin() and end() iterators for that node's children. For
  391. * this reason, you must specify the type of the node's child iterator as an
  392. * additional template parameter.
  393. *
  394. * Specifically, the begin functor must return an iterator whose dereferenced
  395. * value is a @em pointer to a child tree node. For instance, if each node
  396. * tracks its children in an STL container of node* pointers, you can simply
  397. * return that container's begin() iterator.
  398. *
  399. * Alternatively, if a node tracks its children with a classic linked list,
  400. * write a functor returning LLLinkedIter<NODE>.
  401. *
  402. * The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
  403. * template parameters, but is constructed without runtime parameters.
  404. */
  405. template <class NODE, typename CHILDITER>
  406. class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
  407. {
  408. typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
  409. typedef typename super::self_type self_type;
  410. protected:
  411. typedef typename super::ptr_type ptr_type;
  412. // The func_type is different for this: from a NODE pointer, we must
  413. // obtain a CHILDITER.
  414. typedef boost::function<CHILDITER(const ptr_type&)> func_type;
  415. private:
  416. // Upon reaching a given node in our pending list, we need to know whether
  417. // we've already pushed that node's children, so we must associate a bool
  418. // with each node pointer.
  419. typedef std::vector< std::pair<ptr_type, bool> > list_type;
  420. public:
  421. /// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
  422. /// functors to extract the 'child begin' and 'child end' iterators from
  423. /// each node.
  424. LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
  425. : mBeginFunc(beginfunc),
  426. mEndFunc(endfunc),
  427. mSkipAncestors(false)
  428. {
  429. if (! node)
  430. return;
  431. mPending.push_back(typename list_type::value_type(node, false));
  432. makeCurrent();
  433. }
  434. /// Instantiate an LLTreeDFSPostIter to mark the end of the walk
  435. LLTreeDFSPostIter() : mSkipAncestors(false) {}
  436. /// flags iterator logic to skip traversing ancestors of current node on next increment
  437. void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
  438. private:
  439. /// leverage boost::iterator_facade
  440. friend class boost::iterator_core_access;
  441. /// advance
  442. /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
  443. void increment()
  444. {
  445. // Pop the previous current node
  446. mPending.pop_back();
  447. makeCurrent();
  448. }
  449. /// equality
  450. bool equal(const self_type& that) const { return this->mPending == that.mPending; }
  451. /// implement dereference/indirection operators
  452. ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
  453. struct isOpen
  454. {
  455. bool operator()(const typename list_type::value_type& item)
  456. {
  457. return item.second;
  458. }
  459. };
  460. /// Call this each time we change mPending.back() -- that is, every time
  461. /// we're about to change the value returned by dereference(). If we
  462. /// haven't yet pushed the new node's children, do so now.
  463. void makeCurrent()
  464. {
  465. if (mSkipAncestors)
  466. {
  467. mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
  468. mSkipAncestors = false;
  469. }
  470. // Once we've popped the last node, this becomes a no-op.
  471. if (mPending.empty())
  472. return;
  473. // Here mPending.back() holds the node pointer we're proposing to
  474. // dereference next. Have we pushed that node's children yet?
  475. if (mPending.back().second)
  476. return; // if so, it's okay to visit this node now
  477. // We haven't yet pushed this node's children. Do so now. Remember
  478. // that we did -- while the node in question is still back().
  479. mPending.back().second = true;
  480. addChildren(mPending.back().first);
  481. // Now, because we've just changed mPending.back(), make that new node
  482. // current.
  483. makeCurrent();
  484. }
  485. /// Add the direct children of the specified node to mPending
  486. void addChildren(const ptr_type& node)
  487. {
  488. // If we just use push_back() for each child in turn, we'll end up
  489. // processing children in reverse order. We don't want to assume
  490. // CHILDITER is reversible: some of the linked trees we'll be
  491. // processing manage their children using singly-linked lists. So
  492. // figure out how many children there are, grow mPending by that size
  493. // and reverse-copy the children into the new space.
  494. CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
  495. // grow mPending by the number of children
  496. mPending.resize(mPending.size() + std::distance(chi, chend));
  497. // Reverse-copy the children into the newly-expanded space. We can't
  498. // just use std::copy() because the source is a ptr_type, whereas the
  499. // dest is a pair of (ptr_type, bool).
  500. for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
  501. {
  502. pi->first = *chi; // copy the child pointer
  503. pi->second = false; // we haven't yet pushed this child's chldren
  504. }
  505. }
  506. /// list of the nodes yet to be processed
  507. list_type mPending;
  508. /// functor to extract begin() child iterator
  509. func_type mBeginFunc;
  510. /// functor to extract end() child iterator
  511. func_type mEndFunc;
  512. /// flags logic to skip traversal of ancestors of current node
  513. bool mSkipAncestors;
  514. };
  515. /**
  516. * Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
  517. * a breadth-first tree walk through that node and all its descendants.
  518. *
  519. * The begin() LLTreeBFSIter must be instantiated with functors to obtain from
  520. * a given node the begin() and end() iterators of that node's children. For
  521. * this reason, you must specify the type of the node's child iterator as an
  522. * additional template parameter.
  523. *
  524. * Specifically, the begin functor must return an iterator whose dereferenced
  525. * value is a @em pointer to a child tree node. For instance, if each node
  526. * tracks its children in an STL container of node* pointers, you can simply
  527. * return that container's begin() iterator.
  528. *
  529. * Alternatively, if a node tracks its children with a classic linked list,
  530. * write a functor returning LLLinkedIter<NODE>.
  531. *
  532. * The end() LLTreeBFSIter must, of course, match the begin() iterator's
  533. * template parameters, but is constructed without runtime parameters.
  534. */
  535. template <class NODE, typename CHILDITER>
  536. class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
  537. {
  538. typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
  539. typedef typename super::self_type self_type;
  540. protected:
  541. typedef typename super::ptr_type ptr_type;
  542. // The func_type is different for this: from a NODE pointer, we must
  543. // obtain a CHILDITER.
  544. typedef boost::function<CHILDITER(const ptr_type&)> func_type;
  545. private:
  546. // We need a FIFO queue rather than a LIFO stack. Use a deque rather than
  547. // a vector, since vector can't implement pop_front() efficiently.
  548. typedef std::deque<ptr_type> list_type;
  549. public:
  550. /// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
  551. /// functors to extract the 'child begin' and 'child end' iterators from
  552. /// each node.
  553. LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
  554. mBeginFunc(beginfunc),
  555. mEndFunc(endfunc)
  556. {
  557. if (node)
  558. mPending.push_back(node);
  559. }
  560. /// Instantiate an LLTreeBFSIter to mark the end of the walk
  561. LLTreeBFSIter() {}
  562. private:
  563. /// leverage boost::iterator_facade
  564. friend class boost::iterator_core_access;
  565. /// advance
  566. /// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
  567. void increment()
  568. {
  569. // Capture the node we were just looking at
  570. ptr_type current = mPending.front();
  571. // Remove it from mPending so we don't process it again later
  572. mPending.pop_front();
  573. // Add all its children to mPending
  574. CHILDITER chend = mEndFunc(current);
  575. for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
  576. mPending.push_back(*chi);
  577. }
  578. /// equality
  579. bool equal(const self_type& that) const { return this->mPending == that.mPending; }
  580. /// implement dereference/indirection operators
  581. ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
  582. /// list of the nodes yet to be processed
  583. list_type mPending;
  584. /// functor to extract begin() child iterator
  585. func_type mBeginFunc;
  586. /// functor to extract end() child iterator
  587. func_type mEndFunc;
  588. };
  589. /**
  590. * When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
  591. * LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
  592. * LLTreeIter::WalkIter template arg.
  593. */
  594. template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
  595. class LLTreeWalkIter
  596. {
  597. enum { use_a_valid_LLTreeIter_WalkIter_value = false };
  598. public:
  599. /// Bogus constructors for default (unrecognized discriminator) case
  600. template <typename TYPE1, typename TYPE2>
  601. LLTreeWalkIter(TYPE1, TYPE2)
  602. {
  603. BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
  604. }
  605. LLTreeWalkIter()
  606. {
  607. BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
  608. }
  609. };
  610. /// Specialize for LLTreeIter::DFS_PRE
  611. template <class NODE, typename CHILDITER>
  612. class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
  613. public LLTreeDFSIter<NODE, CHILDITER>
  614. {
  615. typedef LLTreeDFSIter<NODE, CHILDITER> super;
  616. public:
  617. /// forward begin ctor
  618. LLTreeWalkIter(const typename super::ptr_type& node,
  619. const typename super::func_type& beginfunc,
  620. const typename super::func_type& endfunc):
  621. super(node, beginfunc, endfunc)
  622. {}
  623. /// forward end ctor
  624. LLTreeWalkIter():
  625. super()
  626. {}
  627. };
  628. /// Specialize for LLTreeIter::DFS_POST
  629. template <class NODE, typename CHILDITER>
  630. class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
  631. public LLTreeDFSPostIter<NODE, CHILDITER>
  632. {
  633. typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
  634. public:
  635. /// forward begin ctor
  636. LLTreeWalkIter(const typename super::ptr_type& node,
  637. const typename super::func_type& beginfunc,
  638. const typename super::func_type& endfunc):
  639. super(node, beginfunc, endfunc)
  640. {}
  641. /// forward end ctor
  642. LLTreeWalkIter():
  643. super()
  644. {}
  645. };
  646. /// Specialize for LLTreeIter::BFS
  647. template <class NODE, typename CHILDITER>
  648. class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
  649. public LLTreeBFSIter<NODE, CHILDITER>
  650. {
  651. typedef LLTreeBFSIter<NODE, CHILDITER> super;
  652. public:
  653. /// forward begin ctor
  654. LLTreeWalkIter(const typename super::ptr_type& node,
  655. const typename super::func_type& beginfunc,
  656. const typename super::func_type& endfunc):
  657. super(node, beginfunc, endfunc)
  658. {}
  659. /// forward end ctor
  660. LLTreeWalkIter():
  661. super()
  662. {}
  663. };
  664. #endif /* ! defined(LL_LLTREEITERATORS_H) */