PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/tests/lltreeiterators_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1213 lines | 803 code | 69 blank | 341 comment | 34 complexity | 06724fee3e7f901bfd87e38367661e4a MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltreeiterators.cpp
  3. * @author Nat Goodspeed
  4. * @date 2008-08-20
  5. * @brief Test of lltreeiterators.h
  6. *
  7. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. // Precompiled header
  29. #include "linden_common.h"
  30. // STL headers
  31. // std headers
  32. #include <iostream>
  33. #include <sstream>
  34. #include <string>
  35. // external library headers
  36. #include <boost/bind.hpp>
  37. #include <boost/range/iterator_range.hpp>
  38. #include <boost/foreach.hpp>
  39. // associated header
  40. #include "../lltreeiterators.h"
  41. #include "../llpointer.h"
  42. #include "../test/lltut.h"
  43. /*****************************************************************************
  44. * tut test group
  45. *****************************************************************************/
  46. namespace tut
  47. {
  48. struct iter_data
  49. {
  50. };
  51. typedef test_group<iter_data> iter_group;
  52. typedef iter_group::object iter_object;
  53. tut::iter_group ig("LLTreeIterators");
  54. } // namespace tut
  55. /*****************************************************************************
  56. * boost::get_pointer() specialization for LLPointer<>
  57. *****************************************************************************/
  58. // This specialization of boost::get_pointer() undoubtedly belongs in
  59. // llmemory.h. It's used by boost::bind() so that you can pass an
  60. // LLPointer<Foo> as well as a Foo* to a functor such as
  61. // boost::bind(&Foo::method, _1).
  62. //namespace boost
  63. //{
  64. template <class NODE>
  65. NODE* get_pointer(const LLPointer<NODE>& ptr) { return ptr.get(); }
  66. //};
  67. /*****************************************************************************
  68. * ScopeLabel
  69. *****************************************************************************/
  70. class ScopeLabel
  71. {
  72. public:
  73. ScopeLabel(const std::string& label): mLabel(label)
  74. {
  75. std::cout << "Entering " << mLabel << '\n';
  76. }
  77. ~ScopeLabel()
  78. {
  79. std::cout << "Leaving " << mLabel << '\n';
  80. }
  81. private:
  82. std::string mLabel;
  83. };
  84. /*****************************************************************************
  85. * Cleanup
  86. *****************************************************************************/
  87. // Yes, we realize this is redundant with auto_ptr and LLPointer and all
  88. // kinds of better mechanisms. But in this particular source file, we need to
  89. // test nodes managed with plain old dumb pointers as well as nodes managed
  90. // with LLPointer, so we introduce this mechanism.
  91. //
  92. // In the general case, when we declare a Cleanup for some pointer, delete the
  93. // pointer when the Cleanup goes out of scope.
  94. template <typename PTRTYPE>
  95. struct Cleanup
  96. {
  97. Cleanup(const PTRTYPE& ptr): mPtr(ptr) {}
  98. ~Cleanup()
  99. {
  100. delete mPtr;
  101. }
  102. PTRTYPE mPtr;
  103. };
  104. // But when the pointer is an LLPointer<something>, Cleanup is a no-op:
  105. // LLPointer will handle the cleanup automagically.
  106. template <typename NODE>
  107. struct Cleanup< LLPointer<NODE> >
  108. {
  109. Cleanup(const LLPointer<NODE>& ptr) {}
  110. ~Cleanup() {}
  111. };
  112. /*****************************************************************************
  113. * Expected
  114. *****************************************************************************/
  115. // Expected is a base class used to capture the expected results -- a sequence
  116. // of string node names -- from one of our traversals of this example data.
  117. // Its subclasses initialize it with a pair of string iterators. It's not
  118. // strictly necessary to customize Expected to model Boost.Range, it's just
  119. // convenient.
  120. struct Expected
  121. {
  122. template <typename ITER>
  123. Expected(ITER begin, ITER end):
  124. strings(begin, end)
  125. {}
  126. /*------ The following are to make Expected work with Boost.Range ------*/
  127. typedef std::vector<std::string> container_type;
  128. typedef container_type::iterator iterator;
  129. typedef container_type::const_iterator const_iterator;
  130. typedef container_type::size_type size_type;
  131. container_type strings;
  132. iterator begin() { return strings.begin(); }
  133. iterator end() { return strings.end(); }
  134. size_type size() { return strings.size(); }
  135. const_iterator begin() const { return strings.begin(); }
  136. const_iterator end() const { return strings.end(); }
  137. };
  138. // We have a couple of generic Expected template subclasses. This list of
  139. // strings is used for the "else" case when all specializations fail.
  140. const char* bad_strings[] = { "FAIL" };
  141. /*****************************************************************************
  142. * verify()
  143. *****************************************************************************/
  144. // test function: given (an object modeling) a Boost.Range of tree nodes,
  145. // compare the sequence of visited node names with a range of expected name
  146. // strings. Report success both with std::cout output and a bool return. The
  147. // string desc parameter is to identify the different tests.
  148. template <typename NODERANGE, typename STRINGRANGE>
  149. bool verify(const std::string& desc, NODERANGE noderange, STRINGRANGE expected)
  150. {
  151. typename boost::range_iterator<NODERANGE>::type
  152. nri = boost::begin(noderange),
  153. nrend = boost::end(noderange);
  154. typename boost::range_iterator<STRINGRANGE>::type
  155. sri = boost::begin(expected),
  156. srend = boost::end(expected);
  157. // We choose to loop over both sequences explicitly rather than using
  158. // std::equal() or std::lexicographical_compare(). The latter tells you
  159. // whether one sequence is *less* than the other -- it doesn't tell you
  160. // equality. std::equal() needs you to verify the sequence lengths ahead
  161. // of time. Anyway, comparing explicitly allows us to report much more
  162. // information about any sequence mismatch.
  163. for ( ; nri != nrend && sri != srend; ++nri, ++sri)
  164. {
  165. if ((*nri)->name() != *sri)
  166. {
  167. std::cout << desc << " mismatch: "
  168. << "expected " << *sri << ", got " << (*nri)->name() << "\n";
  169. return false;
  170. }
  171. }
  172. if (nri != nrend)
  173. {
  174. std::cout << desc << " produced too many items:\n";
  175. for ( ; nri != nrend; ++nri)
  176. {
  177. std::cout << " " << (*nri)->name() << '\n';
  178. }
  179. return false;
  180. }
  181. if (sri != srend)
  182. {
  183. std::cout << desc << " produced too few items, omitting:\n";
  184. for ( ; sri != srend; ++sri)
  185. {
  186. std::cout << " " << *sri << '\n';
  187. }
  188. return false;
  189. }
  190. // std::cout << desc << " test passed\n";
  191. return true;
  192. }
  193. /*****************************************************************************
  194. * PlainNode: LLLinkIter, non-refcounted
  195. *****************************************************************************/
  196. class PlainNode
  197. {
  198. public:
  199. PlainNode(const std::string& name, PlainNode* next=NULL):
  200. mName(name),
  201. mNext(next)
  202. {}
  203. ~PlainNode()
  204. {
  205. delete mNext;
  206. }
  207. std::string name() const { return mName; }
  208. PlainNode* next() const { return mNext; }
  209. public: // if this were 'private', couldn't bind mNext
  210. PlainNode* mNext;
  211. private:
  212. std::string mName;
  213. };
  214. namespace tut
  215. {
  216. template<> template<>
  217. void iter_object::test<1>()
  218. {
  219. // set_test_name("LLLinkedIter -- non-refcounted class");
  220. PlainNode* last(new PlainNode("c"));
  221. PlainNode* second(new PlainNode("b", last));
  222. PlainNode* first(new PlainNode("a", second));
  223. Cleanup<PlainNode*> cleanup(first);
  224. static const char* cseq[] = { "a", "b", "c" };
  225. Expected seq(boost::begin(cseq), boost::end(cseq));
  226. std::string desc1("Iterate by public link member");
  227. // std::cout << desc1 << ":\n";
  228. // Try instantiating an iterator with NULL. This test is less about
  229. // "did we iterate once?" than "did we avoid blowing up?"
  230. for (LLLinkedIter<PlainNode> pni(NULL, boost::bind(&PlainNode::mNext, _1)), end;
  231. pni != end; ++pni)
  232. {
  233. // std::cout << (*pni)->name() << '\n';
  234. ensure("LLLinkedIter<PlainNode>(NULL)", false);
  235. }
  236. ensure(desc1,
  237. verify(desc1,
  238. boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
  239. boost::bind(&PlainNode::mNext, _1)),
  240. LLLinkedIter<PlainNode>()),
  241. seq));
  242. std::string desc2("Iterate by next() method");
  243. // std::cout << desc2 << ":\n";
  244. // for (LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1)); ! (pni == end); ++pni)
  245. // std::cout << (**pni).name() << '\n';
  246. ensure(desc2,
  247. verify(desc2,
  248. boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
  249. boost::bind(&PlainNode::next, _1)),
  250. LLLinkedIter<PlainNode>()),
  251. seq));
  252. {
  253. // LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
  254. // std::cout << "First is " << (*pni++)->name() << '\n';
  255. // std::cout << "Second is " << (*pni )->name() << '\n';
  256. }
  257. {
  258. LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
  259. ensure_equals("first", (*pni++)->name(), "a");
  260. ensure_equals("second", (*pni )->name(), "b");
  261. }
  262. }
  263. } // tut
  264. /*****************************************************************************
  265. * RCNode: LLLinkIter, refcounted
  266. *****************************************************************************/
  267. class RCNode;
  268. typedef LLPointer<RCNode> RCNodePtr;
  269. class RCNode: public LLRefCount
  270. {
  271. public:
  272. RCNode(const std::string& name, const RCNodePtr& next=RCNodePtr()):
  273. mName(name),
  274. mNext(next)
  275. {
  276. // std::cout << "New RCNode(" << mName << ")\n";
  277. }
  278. RCNode(const RCNode& that):
  279. mName(that.mName),
  280. mNext(that.mNext)
  281. {
  282. // std::cout << "Copy RCNode(" << mName << ")\n";
  283. }
  284. virtual ~RCNode();
  285. std::string name() const { return mName; }
  286. RCNodePtr next() const { return mNext; }
  287. public: // if this were 'private', couldn't bind mNext
  288. RCNodePtr mNext;
  289. private:
  290. std::string mName;
  291. };
  292. std::ostream& operator<<(std::ostream& out, const RCNode& node)
  293. {
  294. out << "RCNode(" << node.name() << ')';
  295. return out;
  296. }
  297. // This string contains the node name of the last RCNode destroyed. We use it
  298. // to validate that LLLinkedIter<RCNode> in fact contains LLPointer<RCNode>,
  299. // and that therefore an outstanding LLLinkedIter to an instance of a
  300. // refcounted class suffices to keep that instance alive.
  301. std::string last_RCNode_destroyed;
  302. RCNode::~RCNode()
  303. {
  304. // std::cout << "Kill " << *this << "\n";
  305. last_RCNode_destroyed = mName;
  306. }
  307. namespace tut
  308. {
  309. template<> template<>
  310. void iter_object::test<2>()
  311. {
  312. // set_test_name("LLLinkedIter -- refcounted class");
  313. LLLinkedIter<RCNode> rcni, end2;
  314. {
  315. // ScopeLabel label("inner scope");
  316. RCNodePtr head(new RCNode("x", new RCNode("y", new RCNode("z"))));
  317. // for (rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::mNext, _1)); rcni != end2; ++rcni)
  318. // std::cout << **rcni << '\n';
  319. rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::next, _1));
  320. }
  321. // std::cout << "Now the LLLinkedIter<RCNode> is the only remaining reference to RCNode chain\n";
  322. ensure_equals(last_RCNode_destroyed, "");
  323. ensure(rcni != end2);
  324. ensure_equals((*rcni)->name(), "x");
  325. ++rcni;
  326. ensure_equals(last_RCNode_destroyed, "x");
  327. ensure(rcni != end2);
  328. ensure_equals((*rcni)->name(), "y");
  329. ++rcni;
  330. ensure_equals(last_RCNode_destroyed, "y");
  331. ensure(rcni != end2);
  332. ensure_equals((*rcni)->name(), "z");
  333. ++rcni;
  334. ensure_equals(last_RCNode_destroyed, "z");
  335. ensure(rcni == end2);
  336. }
  337. }
  338. /*****************************************************************************
  339. * TreeNode
  340. *****************************************************************************/
  341. class TreeNode;
  342. typedef LLPointer<TreeNode> TreeNodePtr;
  343. /**
  344. * TreeNode represents a refcounted tree-node class that hasn't (yet) been
  345. * modified to incorporate LLTreeIter methods. This illustrates how you can
  346. * use tree iterators either standalone, or with free functions.
  347. */
  348. class TreeNode: public LLRefCount
  349. {
  350. public:
  351. typedef std::vector<TreeNodePtr> list_type;
  352. typedef list_type::const_iterator child_iterator;
  353. // To avoid cycles, use a "weak" raw pointer for the parent link
  354. TreeNode(const std::string& name, TreeNode* parent=0):
  355. mParent(parent),
  356. mName(name)
  357. {}
  358. TreeNodePtr newChild(const std::string& name)
  359. {
  360. TreeNodePtr child(new TreeNode(name, this));
  361. mChildren.push_back(child);
  362. return child;
  363. }
  364. std::string name() const { return mName; }
  365. TreeNodePtr getParent() const { return mParent; }
  366. child_iterator child_begin() const { return mChildren.begin(); }
  367. child_iterator child_end() const { return mChildren.end(); }
  368. private:
  369. std::string mName;
  370. // To avoid cycles, use a "weak" raw pointer for the parent link
  371. TreeNode* mParent;
  372. list_type mChildren;
  373. };
  374. /**
  375. * This is an example of a helper function to facilitate iterating from a
  376. * TreeNode up to the root or down from the root (see LLTreeIter::RootIter).
  377. *
  378. * Example:
  379. * @code
  380. * BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(somenode))
  381. * {
  382. * std::cout << node->name() << '\n';
  383. * }
  384. * @endcode
  385. */
  386. template <LLTreeIter::RootIter DISCRIM>
  387. boost::iterator_range< LLTreeRootIter<DISCRIM, TreeNode> >
  388. getRootRange(const TreeNodePtr& node)
  389. {
  390. typedef LLTreeRootIter<DISCRIM, TreeNode> iter_type;
  391. typedef boost::iterator_range<iter_type> range_type;
  392. return range_type(iter_type(node, boost::bind(&TreeNode::getParent, _1)),
  393. iter_type());
  394. }
  395. /**
  396. * This is an example of a helper function to facilitate walking a given
  397. * TreeNode's subtree in any supported order (see LLTreeIter::WalkIter).
  398. *
  399. * Example:
  400. * @code
  401. * BOOST_FOREACH(TreeNodePtr node, getWalkRange<LLTreeIter::DFS_PRE>(root))
  402. * {
  403. * std::cout << node->name() << '\n';
  404. * }
  405. * @endcode
  406. */
  407. template <LLTreeIter::WalkIter DISCRIM>
  408. boost::iterator_range< LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> >
  409. getWalkRange(const TreeNodePtr& node)
  410. {
  411. typedef LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> iter_type;
  412. typedef boost::iterator_range<iter_type> range_type;
  413. return range_type(iter_type(node,
  414. boost::bind(&TreeNode::child_begin, _1),
  415. boost::bind(&TreeNode::child_end, _1)),
  416. iter_type());
  417. }
  418. /*****************************************************************************
  419. * EnhancedTreeNode
  420. *****************************************************************************/
  421. class EnhancedTreeNode;
  422. typedef LLPointer<EnhancedTreeNode> EnhancedTreeNodePtr;
  423. /**
  424. * More typically, you enhance the tree-node class itself with template
  425. * methods like the above. This EnhancedTreeNode class illustrates the
  426. * technique. Normally, of course, you'd simply add these methods to TreeNode;
  427. * we put them in a separate class to preserve the undecorated TreeNode class
  428. * to illustrate (and test) the use of plain tree iterators and standalone
  429. * helper functions.
  430. *
  431. * We originally implemented EnhancedTreeNode as a subclass of TreeNode -- but
  432. * because TreeNode stores and manipulates TreeNodePtrs and TreeNode*s,
  433. * reusing its methods required so much ugly downcast logic that we gave up
  434. * and restated the whole class. Bear in mind that logically these aren't two
  435. * separate classes; logically they're two snapshots of the @em same class at
  436. * different moments in time.
  437. */
  438. class EnhancedTreeNode: public LLRefCount
  439. {
  440. public:
  441. /*-------------- The following is restated from TreeNode ---------------*/
  442. typedef std::vector<EnhancedTreeNodePtr> list_type;
  443. typedef list_type::const_iterator child_iterator;
  444. // To avoid cycles, use a "weak" raw pointer for the parent link
  445. EnhancedTreeNode(const std::string& name, EnhancedTreeNode* parent=0):
  446. mParent(parent),
  447. mName(name)
  448. {}
  449. EnhancedTreeNodePtr newChild(const std::string& name)
  450. {
  451. EnhancedTreeNodePtr child(new EnhancedTreeNode(name, this));
  452. mChildren.push_back(child);
  453. return child;
  454. }
  455. std::string name() const { return mName; }
  456. EnhancedTreeNodePtr getParent() const { return mParent; }
  457. child_iterator child_begin() const { return mChildren.begin(); }
  458. child_iterator child_end() const { return mChildren.end(); }
  459. private:
  460. std::string mName;
  461. // To avoid cycles, use a "weak" raw pointer for the parent link
  462. EnhancedTreeNode* mParent;
  463. list_type mChildren;
  464. public:
  465. /*----- End of TreeNode; what follows is new with EnhancedTreeNode -----*/
  466. /**
  467. * Because the type of the iterator range returned by getRootRange()
  468. * depends on the discriminator enum value, instead of a simple typedef we
  469. * use a templated struct. Example usage:
  470. *
  471. * @code
  472. * for (EnhancedTreeNode::root_range<LLTreeIter::UP>::type range =
  473. * somenode->getRootRange<LLTreeIter::UP>();
  474. * range.first != range.second; ++range.first)
  475. * {
  476. * std::cout << (*range.first)->name() << '\n';
  477. * }
  478. * @endcode
  479. */
  480. template <LLTreeIter::RootIter DISCRIM>
  481. struct root_range
  482. {
  483. typedef boost::iterator_range< LLTreeRootIter<DISCRIM, EnhancedTreeNode> > type;
  484. };
  485. /**
  486. * Helper method for walking up to (or down from) the tree root. See
  487. * LLTreeIter::RootIter.
  488. *
  489. * Example usage:
  490. * @code
  491. * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange<LLTreeIter::UP>())
  492. * {
  493. * std::cout << node->name() << '\n';
  494. * }
  495. * @endcode
  496. */
  497. template <LLTreeIter::RootIter DISCRIM>
  498. typename root_range<DISCRIM>::type getRootRange() const
  499. {
  500. typedef typename root_range<DISCRIM>::type range_type;
  501. typedef typename range_type::iterator iter_type;
  502. return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
  503. boost::bind(&EnhancedTreeNode::getParent, _1)),
  504. iter_type());
  505. }
  506. /**
  507. * Because the type of the iterator range returned by getWalkRange()
  508. * depends on the discriminator enum value, instead of a simple typedef we
  509. * use a templated stuct. Example usage:
  510. *
  511. * @code
  512. * for (EnhancedTreeNode::walk_range<LLTreeIter::DFS_PRE>::type range =
  513. * somenode->getWalkRange<LLTreeIter::DFS_PRE>();
  514. * range.first != range.second; ++range.first)
  515. * {
  516. * std::cout << (*range.first)->name() << '\n';
  517. * }
  518. * @endcode
  519. */
  520. template <LLTreeIter::WalkIter DISCRIM>
  521. struct walk_range
  522. {
  523. typedef boost::iterator_range< LLTreeWalkIter<DISCRIM,
  524. EnhancedTreeNode,
  525. EnhancedTreeNode::child_iterator> > type;
  526. };
  527. /**
  528. * Helper method for walking a given node's subtree in any supported
  529. * order (see LLTreeIter::WalkIter).
  530. *
  531. * Example usage:
  532. * @code
  533. * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange<LLTreeIter::DFS_PRE>())
  534. * {
  535. * std::cout << node->name() << '\n';
  536. * }
  537. * @endcode
  538. */
  539. template <LLTreeIter::WalkIter DISCRIM>
  540. typename walk_range<DISCRIM>::type getWalkRange() const
  541. {
  542. typedef typename walk_range<DISCRIM>::type range_type;
  543. typedef typename range_type::iterator iter_type;
  544. return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
  545. boost::bind(&EnhancedTreeNode::child_begin, _1),
  546. boost::bind(&EnhancedTreeNode::child_end, _1)),
  547. iter_type());
  548. }
  549. };
  550. /*****************************************************************************
  551. * PlainTree
  552. *****************************************************************************/
  553. struct PlainTree
  554. {
  555. PlainTree(const std::string& name, PlainTree* parent=0):
  556. mName(name),
  557. mParent(parent),
  558. mNextSibling(0),
  559. mFirstChild(0)
  560. {
  561. mLastChildLink = &mFirstChild;
  562. }
  563. ~PlainTree()
  564. {
  565. delete mNextSibling;
  566. delete mFirstChild;
  567. }
  568. PlainTree* newChild(const std::string& name)
  569. {
  570. PlainTree* child(new PlainTree(name, this));
  571. *mLastChildLink = child;
  572. mLastChildLink = &child->mNextSibling;
  573. return child;
  574. }
  575. std::string name() const { return mName; }
  576. std::string mName;
  577. PlainTree* mParent;
  578. PlainTree* mNextSibling;
  579. PlainTree* mFirstChild;
  580. PlainTree** mLastChildLink;
  581. };
  582. // This "classic" tree tracks each node's children with a linked list anchored
  583. // at the parent's mFirstChild and linked through each child's mNextSibling.
  584. // LLTreeDFSIter<> and LLTreeBFSIter<> need functors to return begin()/end()
  585. // iterators over a given node's children. But because this tree's children
  586. // aren't stored in an STL container, we can't just export that container's
  587. // begin()/end(). Instead we'll use LLLinkedIter<> to view the hand-maintained
  588. // linked list as an iterator range. The straightforward way to do that would
  589. // be to add child_begin() and child_end() methods. But let's say (for the
  590. // sake of argument) that this struct is so venerable we don't dare modify it
  591. // even to add new methods. Well, we can use free functions (or functors) too.
  592. LLLinkedIter<PlainTree> PlainTree_child_begin(PlainTree* node)
  593. {
  594. return LLLinkedIter<PlainTree>(node->mFirstChild, boost::bind(&PlainTree::mNextSibling, _1));
  595. }
  596. LLLinkedIter<PlainTree> PlainTree_child_end(PlainTree* node)
  597. {
  598. return LLLinkedIter<PlainTree>();
  599. }
  600. /**
  601. * This is an example of a helper function to facilitate iterating from a
  602. * PlainTree up to the root or down from the root (see LLTreeIter::RootIter).
  603. * Note that we're simply overloading the same getRootRange() helper function
  604. * name we used for TreeNode.
  605. *
  606. * Example:
  607. * @code
  608. * BOOST_FOREACH(PlainTree* node, getRootRange<LLTreeIter::UP>(somenode))
  609. * {
  610. * std::cout << node->name() << '\n';
  611. * }
  612. * @endcode
  613. */
  614. template <LLTreeIter::RootIter DISCRIM>
  615. boost::iterator_range< LLTreeRootIter<DISCRIM, PlainTree> >
  616. getRootRange(PlainTree* node)
  617. {
  618. typedef LLTreeRootIter<DISCRIM, PlainTree> iter_type;
  619. typedef boost::iterator_range<iter_type> range_type;
  620. return range_type(iter_type(node, boost::bind(&PlainTree::mParent, _1)),
  621. iter_type());
  622. }
  623. /**
  624. * This is an example of a helper function to facilitate walking a given
  625. * PlainTree's subtree in any supported order (see LLTreeIter::WalkIter). Note
  626. * that we're simply overloading the same getWalkRange() helper function name
  627. * we used for TreeNode.
  628. *
  629. * Example:
  630. * @code
  631. * BOOST_FOREACH(PlainTree* node, getWalkRange<LLTreeIter::DFS_PRE>(root))
  632. * {
  633. * std::cout << node->name() << '\n';
  634. * }
  635. * @endcode
  636. */
  637. template <LLTreeIter::WalkIter DISCRIM>
  638. boost::iterator_range< LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > >
  639. getWalkRange(PlainTree* node)
  640. {
  641. typedef LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > iter_type;
  642. typedef boost::iterator_range<iter_type> range_type;
  643. return range_type(iter_type(node,
  644. PlainTree_child_begin,
  645. PlainTree_child_end),
  646. iter_type());
  647. }
  648. // We could go through the exercise of writing EnhancedPlainTree containing
  649. // root_range, getRootRange(), walk_range and getWalkRange() members -- but we
  650. // won't. See EnhancedTreeNode for examples.
  651. /*****************************************************************************
  652. * Generic tree test data
  653. *****************************************************************************/
  654. template <class NODE>
  655. typename LLPtrTo<NODE>::type example_tree()
  656. {
  657. typedef typename LLPtrTo<NODE>::type NodePtr;
  658. NodePtr root(new NODE("root"));
  659. NodePtr A(root->newChild("A"));
  660. NodePtr A1(A->newChild("A1"));
  661. /* NodePtr A1a*/(A1->newChild("A1a"));
  662. /* NodePtr A1b*/(A1->newChild("A1b"));
  663. /* NodePtr A1c*/(A1->newChild("A1c"));
  664. NodePtr A2(A->newChild("A2"));
  665. /* NodePtr A2a*/(A2->newChild("A2a"));
  666. /* NodePtr A2b*/(A2->newChild("A2b"));
  667. /* NodePtr A2c*/(A2->newChild("A2c"));
  668. NodePtr A3(A->newChild("A3"));
  669. /* NodePtr A3a*/(A3->newChild("A3a"));
  670. /* NodePtr A3b*/(A3->newChild("A3b"));
  671. /* NodePtr A3c*/(A3->newChild("A3c"));
  672. NodePtr B(root->newChild("B"));
  673. NodePtr B1(B->newChild("B1"));
  674. /* NodePtr B1a*/(B1->newChild("B1a"));
  675. /* NodePtr B1b*/(B1->newChild("B1b"));
  676. /* NodePtr B1c*/(B1->newChild("B1c"));
  677. NodePtr B2(B->newChild("B2"));
  678. /* NodePtr B2a*/(B2->newChild("B2a"));
  679. /* NodePtr B2b*/(B2->newChild("B2b"));
  680. /* NodePtr B2c*/(B2->newChild("B2c"));
  681. NodePtr B3(B->newChild("B3"));
  682. /* NodePtr B3a*/(B3->newChild("B3a"));
  683. /* NodePtr B3b*/(B3->newChild("B3b"));
  684. /* NodePtr B3c*/(B3->newChild("B3c"));
  685. NodePtr C(root->newChild("C"));
  686. NodePtr C1(C->newChild("C1"));
  687. /* NodePtr C1a*/(C1->newChild("C1a"));
  688. /* NodePtr C1b*/(C1->newChild("C1b"));
  689. /* NodePtr C1c*/(C1->newChild("C1c"));
  690. NodePtr C2(C->newChild("C2"));
  691. /* NodePtr C2a*/(C2->newChild("C2a"));
  692. /* NodePtr C2b*/(C2->newChild("C2b"));
  693. /* NodePtr C2c*/(C2->newChild("C2c"));
  694. NodePtr C3(C->newChild("C3"));
  695. /* NodePtr C3a*/(C3->newChild("C3a"));
  696. /* NodePtr C3b*/(C3->newChild("C3b"));
  697. /* NodePtr C3c*/(C3->newChild("C3c"));
  698. return root;
  699. }
  700. // WalkExpected<WalkIter> is the list of string node names we expect from a
  701. // WalkIter traversal of our example_tree() data.
  702. template <LLTreeIter::WalkIter DISCRIM>
  703. struct WalkExpected: public Expected
  704. {
  705. // Initialize with bad_strings: we don't expect to use this generic case,
  706. // only the specializations. Note that for a classic C-style array we must
  707. // pass a pair of iterators rather than extracting boost::begin() and
  708. // boost::end() within the target constructor: a template ctor accepts
  709. // these classic C-style arrays as char** rather than char*[length]. Oh well.
  710. WalkExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
  711. };
  712. // list of string node names we expect from traversing example_tree() in
  713. // DFS_PRE order
  714. const char* dfs_pre_strings[] =
  715. {
  716. "root",
  717. "A",
  718. "A1",
  719. "A1a",
  720. "A1b",
  721. "A1c",
  722. "A2",
  723. "A2a",
  724. "A2b",
  725. "A2c",
  726. "A3",
  727. "A3a",
  728. "A3b",
  729. "A3c",
  730. "B",
  731. "B1",
  732. "B1a",
  733. "B1b",
  734. "B1c",
  735. "B2",
  736. "B2a",
  737. "B2b",
  738. "B2c",
  739. "B3",
  740. "B3a",
  741. "B3b",
  742. "B3c",
  743. "C",
  744. "C1",
  745. "C1a",
  746. "C1b",
  747. "C1c",
  748. "C2",
  749. "C2a",
  750. "C2b",
  751. "C2c",
  752. "C3",
  753. "C3a",
  754. "C3b",
  755. "C3c"
  756. };
  757. // specialize WalkExpected<DFS_PRE> with the expected strings
  758. template <>
  759. struct WalkExpected<LLTreeIter::DFS_PRE>: public Expected
  760. {
  761. WalkExpected(): Expected(boost::begin(dfs_pre_strings), boost::end(dfs_pre_strings)) {}
  762. };
  763. // list of string node names we expect from traversing example_tree() in
  764. // DFS_POST order
  765. const char* dfs_post_strings[] =
  766. {
  767. "A1a",
  768. "A1b",
  769. "A1c",
  770. "A1",
  771. "A2a",
  772. "A2b",
  773. "A2c",
  774. "A2",
  775. "A3a",
  776. "A3b",
  777. "A3c",
  778. "A3",
  779. "A",
  780. "B1a",
  781. "B1b",
  782. "B1c",
  783. "B1",
  784. "B2a",
  785. "B2b",
  786. "B2c",
  787. "B2",
  788. "B3a",
  789. "B3b",
  790. "B3c",
  791. "B3",
  792. "B",
  793. "C1a",
  794. "C1b",
  795. "C1c",
  796. "C1",
  797. "C2a",
  798. "C2b",
  799. "C2c",
  800. "C2",
  801. "C3a",
  802. "C3b",
  803. "C3c",
  804. "C3",
  805. "C",
  806. "root"
  807. };
  808. // specialize WalkExpected<DFS_POST> with the expected strings
  809. template <>
  810. struct WalkExpected<LLTreeIter::DFS_POST>: public Expected
  811. {
  812. WalkExpected(): Expected(boost::begin(dfs_post_strings), boost::end(dfs_post_strings)) {}
  813. };
  814. // list of string node names we expect from traversing example_tree() in BFS order
  815. const char* bfs_strings[] =
  816. {
  817. "root",
  818. "A",
  819. "B",
  820. "C",
  821. "A1",
  822. "A2",
  823. "A3",
  824. "B1",
  825. "B2",
  826. "B3",
  827. "C1",
  828. "C2",
  829. "C3",
  830. "A1a",
  831. "A1b",
  832. "A1c",
  833. "A2a",
  834. "A2b",
  835. "A2c",
  836. "A3a",
  837. "A3b",
  838. "A3c",
  839. "B1a",
  840. "B1b",
  841. "B1c",
  842. "B2a",
  843. "B2b",
  844. "B2c",
  845. "B3a",
  846. "B3b",
  847. "B3c",
  848. "C1a",
  849. "C1b",
  850. "C1c",
  851. "C2a",
  852. "C2b",
  853. "C2c",
  854. "C3a",
  855. "C3b",
  856. "C3c"
  857. };
  858. // specialize WalkExpected<BFS> with the expected strings
  859. template <>
  860. struct WalkExpected<LLTreeIter::BFS>: public Expected
  861. {
  862. WalkExpected(): Expected(boost::begin(bfs_strings), boost::end(bfs_strings)) {}
  863. };
  864. // extract a particular "arbitrary" node from the example_tree() data: the
  865. // second (middle) node at each child level
  866. template <class NODE, typename CHILDITER>
  867. typename LLPtrTo<NODE>::type
  868. get_B2b(const typename LLPtrTo<NODE>::type& root,
  869. const boost::function<CHILDITER(const typename LLPtrTo<NODE>::type&)>& child_begin)
  870. {
  871. typedef typename LLPtrTo<NODE>::type NodePtr;
  872. CHILDITER Bi(child_begin(root));
  873. ++Bi;
  874. NodePtr B(*Bi);
  875. CHILDITER B2i(child_begin(B));
  876. ++B2i;
  877. NodePtr B2(*B2i);
  878. CHILDITER B2bi(child_begin(B2));
  879. ++B2bi;
  880. NodePtr B2b(*B2bi);
  881. return B2b;
  882. }
  883. // RootExpected<RootIter> is the list of string node names we expect from a
  884. // RootIter traversal of our example_tree() data.
  885. template <LLTreeIter::RootIter DISCRIM>
  886. struct RootExpected: public Expected
  887. {
  888. // Initialize with bad_strings: we don't expect to use this generic case,
  889. // only the specializations.
  890. RootExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
  891. };
  892. // list of string node names we expect from traversing UP from
  893. // example_tree()'s B2b node
  894. const char* up_from_B2b[] =
  895. {
  896. "B2b",
  897. "B2",
  898. "B",
  899. "root"
  900. };
  901. // specialize RootExpected<UP> with the expected strings
  902. template <>
  903. struct RootExpected<LLTreeIter::UP>: public Expected
  904. {
  905. RootExpected(): Expected(boost::begin(up_from_B2b), boost::end(up_from_B2b)) {}
  906. };
  907. // list of string node names we expect from traversing DOWN to
  908. // example_tree()'s B2b node
  909. const char* down_to_B2b[] =
  910. {
  911. "root",
  912. "B",
  913. "B2",
  914. "B2b"
  915. };
  916. // specialize RootExpected<DOWN> with the expected strings
  917. template <>
  918. struct RootExpected<LLTreeIter::DOWN>: public Expected
  919. {
  920. RootExpected(): Expected(boost::begin(down_to_B2b), boost::end(down_to_B2b)) {}
  921. };
  922. /*****************************************************************************
  923. * Generic tree test functions
  924. *****************************************************************************/
  925. template<LLTreeIter::RootIter DISCRIM, class NODE, typename PARENTFUNC>
  926. bool LLTreeRootIter_test(const std::string& itername, const std::string& nodename,
  927. const typename LLPtrTo<NODE>::type& node,
  928. PARENTFUNC parentfunc)
  929. {
  930. std::ostringstream desc;
  931. desc << itername << '<' << nodename << "> from " << node->name();
  932. if (! verify(desc.str(),
  933. boost::make_iterator_range(LLTreeRootIter<DISCRIM, NODE>(node, parentfunc),
  934. LLTreeRootIter<DISCRIM, NODE>()),
  935. RootExpected<DISCRIM>()))
  936. return false;
  937. // std::cout << desc.str() << '\n';
  938. // Try instantiating an iterator with NULL (that is, a default-constructed
  939. // node pointer). This test is less about "did we iterate once?" than "did
  940. // we avoid blowing up?"
  941. for (LLTreeRootIter<DISCRIM, NODE> hri = LLTreeRootIter<DISCRIM, NODE>(typename LLPtrTo<NODE>::type(), parentfunc), hrend;
  942. hri != hrend; /* ++hri */) // incrementing is moot, and MSVC complains
  943. {
  944. // std::cout << nodename << '(' << (*hri)->name() << ")\n";
  945. std::cout << itername << '<' << nodename << ">(NULL)\n";
  946. return false;
  947. }
  948. return true;
  949. }
  950. template<class NODE, typename CHILDITER, typename PARENTFUNC, typename CHILDFUNC>
  951. bool LLTreeUpIter_test(const std::string& nodename, PARENTFUNC parentfunc, CHILDFUNC childfunc)
  952. {
  953. bool success = true;
  954. typedef typename LLPtrTo<NODE>::type ptr_type;
  955. ptr_type root(example_tree<NODE>());
  956. Cleanup<ptr_type> cleanup(root);
  957. ptr_type B2b(get_B2b<NODE, CHILDITER>(root, childfunc));
  958. if (! LLTreeRootIter_test<LLTreeIter::UP, NODE>("LLTreeUpIter", nodename, B2b, parentfunc))
  959. success = false;
  960. if (! LLTreeRootIter_test<LLTreeIter::DOWN, NODE>("LLTreeDownIter", nodename, B2b, parentfunc))
  961. success = false;
  962. return success;
  963. }
  964. template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER,
  965. typename CHILDBEGINFUNC, typename CHILDENDFUNC>
  966. bool LLTreeWalkIter_test(const std::string& itername, const std::string& nodename,
  967. CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
  968. {
  969. typename LLPtrTo<NODE>::type root(example_tree<NODE>());
  970. Cleanup<typename LLPtrTo<NODE>::type> cleanup(root);
  971. std::ostringstream desc;
  972. desc << itername << '<' << nodename << "> from " << root->name();
  973. if (! verify(desc.str(),
  974. boost::make_iterator_range(LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(root,
  975. childbegin,
  976. childend),
  977. LLTreeWalkIter<DISCRIM, NODE, CHILDITER>()),
  978. WalkExpected<DISCRIM>()))
  979. return false;
  980. // Try instantiating an iterator with NULL (that is, a default-constructed
  981. // node pointer). This test is less about "did we iterate once?" than "did
  982. // we avoid blowing up?"
  983. for (LLTreeWalkIter<DISCRIM, NODE, CHILDITER> twi = LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(typename LLPtrTo<NODE>::type(),
  984. childbegin,
  985. childend),
  986. twend;
  987. twi != twend; /* ++twi */) // incrementing is moot, and MSVC complains
  988. {
  989. std::cout << itername << '<' << nodename << ">(NULL)\n";
  990. return false;
  991. }
  992. return true;
  993. }
  994. template <class NODE, typename CHILDITER,
  995. typename PARENTFUNC, typename CHILDBEGINFUNC, typename CHILDENDFUNC>
  996. bool LLTreeIter_tests(const std::string& nodename,
  997. PARENTFUNC parentfunc, CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
  998. {
  999. bool success = true;
  1000. if (! LLTreeUpIter_test<NODE, CHILDITER>(nodename, parentfunc, childbegin))
  1001. success = false;
  1002. /*==========================================================================*|
  1003. LLTreeIter_test<NODE, LLTreeDFSIter<NODE, CHILDITER> >("LLTreeDFSIter", nodename,
  1004. childbegin, childend);
  1005. LLTreeIter_test<NODE, LLTreeDFSPostIter<NODE, CHILDITER> >("LLTreeDFSPostIter", nodename,
  1006. childbegin, childend);
  1007. LLTreeIter_test<NODE, LLTreeBFSIter<NODE, CHILDITER> >("LLTreeBFSIter", nodename,
  1008. childbegin, childend);
  1009. |*==========================================================================*/
  1010. if (! LLTreeWalkIter_test<LLTreeIter::DFS_PRE, NODE, CHILDITER>("LLTreeDFSIter", nodename,
  1011. childbegin, childend))
  1012. success = false;
  1013. if (! LLTreeWalkIter_test<LLTreeIter::DFS_POST, NODE, CHILDITER>("LLTreeDFSPostIter", nodename,
  1014. childbegin, childend))
  1015. success = false;
  1016. if (! LLTreeWalkIter_test<LLTreeIter::BFS, NODE, CHILDITER>("LLTreeBFSIter", nodename,
  1017. childbegin, childend))
  1018. success = false;
  1019. return success;
  1020. }
  1021. namespace tut
  1022. {
  1023. template<> template<>
  1024. void iter_object::test<3>()
  1025. {
  1026. // set_test_name("LLTreeIter tests");
  1027. ensure(LLTreeIter_tests<TreeNode, TreeNode::child_iterator>
  1028. ("TreeNode",
  1029. boost::bind(&TreeNode::getParent, _1),
  1030. boost::bind(&TreeNode::child_begin, _1),
  1031. boost::bind(&TreeNode::child_end, _1)));
  1032. ensure(LLTreeIter_tests<PlainTree, LLLinkedIter<PlainTree> >
  1033. ("PlainTree",
  1034. boost::bind(&PlainTree::mParent, _1),
  1035. PlainTree_child_begin,
  1036. PlainTree_child_end));
  1037. }
  1038. template<> template<>
  1039. void iter_object::test<4>()
  1040. {
  1041. // set_test_name("getRootRange() tests");
  1042. // This test function illustrates the looping techniques described in the
  1043. // comments for the getRootRange() free function, the
  1044. // EnhancedTreeNode::root_range template and the
  1045. // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH()
  1046. // forms are more succinct.
  1047. TreeNodePtr tnroot(example_tree<TreeNode>());
  1048. TreeNodePtr tnB2b(get_B2b<TreeNode, TreeNode::child_iterator>
  1049. (tnroot, boost::bind(&TreeNode::child_begin, _1)));
  1050. std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange<LLTreeIter::UP>(tnB2b))");
  1051. // std::cout << desc1 << "\n";
  1052. // Although we've commented out the output statement, ensure that the
  1053. // loop construct is still valid, as promised by the getRootRange()
  1054. // documentation.
  1055. BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(tnB2b))
  1056. {
  1057. // std::cout << node->name() << '\n';
  1058. }
  1059. ensure(desc1,
  1060. verify(desc1, getRootRange<LLTreeIter::UP>(tnB2b), RootExpected<LLTreeIter::UP>()));
  1061. EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
  1062. EnhancedTreeNodePtr etnB2b(get_B2b<EnhancedTreeNode, EnhancedTreeNode::child_iterator>
  1063. (etnroot, boost::bind(&EnhancedTreeNode::child_begin, _1)));
  1064. // std::cout << "EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =\n"
  1065. // << " etnB2b->getRootRange<LLTreeIter::DOWN>();\n"
  1066. // << "for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();\n"
  1067. // << " ri != range.end(); ++ri)\n";
  1068. EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =
  1069. etnB2b->getRootRange<LLTreeIter::DOWN>();
  1070. for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();
  1071. ri != range.end(); ++ri)
  1072. {
  1073. // std::cout << (*ri)->name() << '\n';
  1074. }
  1075. std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())");
  1076. // std::cout << desc2 << '\n';
  1077. BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())
  1078. {
  1079. // std::cout << node->name() << '\n';
  1080. }
  1081. ensure(desc2,
  1082. verify(desc2, etnB2b->getRootRange<LLTreeIter::UP>(), RootExpected<LLTreeIter::UP>()));
  1083. }
  1084. template<> template<>
  1085. void iter_object::test<5>()
  1086. {
  1087. // set_test_name("getWalkRange() tests");
  1088. // This test function doesn't illustrate the looping permutations for
  1089. // getWalkRange(); see getRootRange_tests() for such examples. This
  1090. // function simply verifies that they all work.
  1091. // TreeNode, using helper function
  1092. TreeNodePtr tnroot(example_tree<TreeNode>());
  1093. std::string desc_tnpre("getWalkRange<LLTreeIter::DFS_PRE>(tnroot)");
  1094. ensure(desc_tnpre,
  1095. verify(desc_tnpre,
  1096. getWalkRange<LLTreeIter::DFS_PRE>(tnroot),
  1097. WalkExpected<LLTreeIter::DFS_PRE>()));
  1098. std::string desc_tnpost("getWalkRange<LLTreeIter::DFS_POST>(tnroot)");
  1099. ensure(desc_tnpost,
  1100. verify(desc_tnpost,
  1101. getWalkRange<LLTreeIter::DFS_POST>(tnroot),
  1102. WalkExpected<LLTreeIter::DFS_POST>()));
  1103. std::string desc_tnb("getWalkRange<LLTreeIter::BFS>(tnroot)");
  1104. ensure(desc_tnb,
  1105. verify(desc_tnb,
  1106. getWalkRange<LLTreeIter::BFS>(tnroot),
  1107. WalkExpected<LLTreeIter::BFS>()));
  1108. // EnhancedTreeNode, using method
  1109. EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
  1110. std::string desc_etnpre("etnroot->getWalkRange<LLTreeIter::DFS_PRE>()");
  1111. ensure(desc_etnpre,
  1112. verify(desc_etnpre,
  1113. etnroot->getWalkRange<LLTreeIter::DFS_PRE>(),
  1114. WalkExpected<LLTreeIter::DFS_PRE>()));
  1115. std::string desc_etnpost("etnroot->getWalkRange<LLTreeIter::DFS_POST>()");
  1116. ensure(desc_etnpost,
  1117. verify(desc_etnpost,
  1118. etnroot->getWalkRange<LLTreeIter::DFS_POST>(),
  1119. WalkExpected<LLTreeIter::DFS_POST>()));
  1120. std::string desc_etnb("etnroot->getWalkRange<LLTreeIter::BFS>()");
  1121. ensure(desc_etnb,
  1122. verify(desc_etnb,
  1123. etnroot->getWalkRange<LLTreeIter::BFS>(),
  1124. WalkExpected<LLTreeIter::BFS>()));
  1125. // PlainTree, using helper function
  1126. PlainTree* ptroot(example_tree<PlainTree>());
  1127. Cleanup<PlainTree*> cleanup(ptroot);
  1128. std::string desc_ptpre("getWalkRange<LLTreeIter::DFS_PRE>(ptroot)");
  1129. ensure(desc_ptpre,
  1130. verify(desc_ptpre,
  1131. getWalkRange<LLTreeIter::DFS_PRE>(ptroot),
  1132. WalkExpected<LLTreeIter::DFS_PRE>()));
  1133. std::string desc_ptpost("getWalkRange<LLTreeIter::DFS_POST>(ptroot)");
  1134. ensure(desc_ptpost,
  1135. verify(desc_ptpost,
  1136. getWalkRange<LLTreeIter::DFS_POST>(ptroot),
  1137. WalkExpected<LLTreeIter::DFS_POST>()));
  1138. std::string desc_ptb("getWalkRange<LLTreeIter::BFS>(ptroot)");
  1139. ensure(desc_ptb,
  1140. verify(desc_ptb,
  1141. getWalkRange<LLTreeIter::BFS>(ptroot),
  1142. WalkExpected<LLTreeIter::BFS>()));
  1143. }
  1144. } // tut