PageRenderTime 3191ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/lldependencies.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 799 lines | 437 code | 61 blank | 301 comment | 44 complexity | 4631b347057d08f8ced23dc720165299 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lldependencies.h
  3. * @author Nat Goodspeed
  4. * @date 2008-09-17
  5. * @brief LLDependencies: a generic mechanism for expressing "b must follow a,
  6. * but precede c"
  7. *
  8. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  9. * Second Life Viewer Source Code
  10. * Copyright (C) 2010, Linden Research, Inc.
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation;
  15. * version 2.1 of the License only.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  25. *
  26. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  27. * $/LicenseInfo$
  28. */
  29. #if ! defined(LL_LLDEPENDENCIES_H)
  30. #define LL_LLDEPENDENCIES_H
  31. #include <string>
  32. #include <vector>
  33. #include <set>
  34. #include <map>
  35. #include <stdexcept>
  36. #include <iosfwd>
  37. #include <boost/iterator/transform_iterator.hpp>
  38. #include <boost/iterator/indirect_iterator.hpp>
  39. #include <boost/range/iterator_range.hpp>
  40. #include <boost/function.hpp>
  41. #include <boost/bind.hpp>
  42. /*****************************************************************************
  43. * Utilities
  44. *****************************************************************************/
  45. /**
  46. * generic range transformer: given a range acceptable to Boost.Range (e.g. a
  47. * standard container, an iterator pair, ...) and a unary function to apply to
  48. * each element of the range, make a corresponding range that lazily applies
  49. * that function to each element on dereferencing.
  50. */
  51. template<typename FUNCTION, typename RANGE>
  52. inline
  53. boost::iterator_range<boost::transform_iterator<FUNCTION,
  54. typename boost::range_const_iterator<RANGE>::type> >
  55. make_transform_range(const RANGE& range, FUNCTION function)
  56. {
  57. // shorthand for the iterator type embedded in our return type
  58. typedef boost::transform_iterator<FUNCTION, typename boost::range_const_iterator<RANGE>::type>
  59. transform_iterator;
  60. return boost::make_iterator_range(transform_iterator(boost::begin(range), function),
  61. transform_iterator(boost::end(range), function));
  62. }
  63. /// non-const version of make_transform_range()
  64. template<typename FUNCTION, typename RANGE>
  65. inline
  66. boost::iterator_range<boost::transform_iterator<FUNCTION,
  67. typename boost::range_iterator<RANGE>::type> >
  68. make_transform_range(RANGE& range, FUNCTION function)
  69. {
  70. // shorthand for the iterator type embedded in our return type
  71. typedef boost::transform_iterator<FUNCTION, typename boost::range_iterator<RANGE>::type>
  72. transform_iterator;
  73. return boost::make_iterator_range(transform_iterator(boost::begin(range), function),
  74. transform_iterator(boost::end(range), function));
  75. }
  76. /**
  77. * From any range compatible with Boost.Range, instantiate any class capable
  78. * of accepting an iterator pair.
  79. */
  80. template<class TYPE>
  81. struct instance_from_range: public TYPE
  82. {
  83. template<typename RANGE>
  84. instance_from_range(RANGE range):
  85. TYPE(boost::begin(range), boost::end(range))
  86. {}
  87. };
  88. /*****************************************************************************
  89. * LLDependencies
  90. *****************************************************************************/
  91. /**
  92. * LLDependencies components that should not be reinstantiated for each KEY,
  93. * NODE specialization
  94. */
  95. class LL_COMMON_API LLDependenciesBase
  96. {
  97. public:
  98. virtual ~LLDependenciesBase() {}
  99. /**
  100. * Exception thrown by sort() if there's a cycle
  101. */
  102. struct Cycle: public std::runtime_error
  103. {
  104. Cycle(const std::string& what): std::runtime_error(what) {}
  105. };
  106. /**
  107. * Provide a short description of this LLDependencies instance on the
  108. * specified output stream, assuming that its KEY type has an operator<<()
  109. * that works with std::ostream.
  110. *
  111. * Pass @a full as @c false to omit any keys without dependency constraints.
  112. */
  113. virtual std::ostream& describe(std::ostream& out, bool full=true) const;
  114. /// describe() to a string
  115. virtual std::string describe(bool full=true) const;
  116. protected:
  117. typedef std::vector< std::pair<int, int> > EdgeList;
  118. typedef std::vector<int> VertexList;
  119. VertexList topo_sort(int vertices, const EdgeList& edges) const;
  120. /**
  121. * refpair is specifically intended to capture a pair of references. This
  122. * is better than std::pair<T1&, T2&> because some implementations of
  123. * std::pair's ctor accept const references to the two types. If the
  124. * types are themselves references, this results in an illegal reference-
  125. * to-reference.
  126. */
  127. template<typename T1, typename T2>
  128. struct refpair
  129. {
  130. refpair(T1 value1, T2 value2):
  131. first(value1),
  132. second(value2)
  133. {}
  134. T1 first;
  135. T2 second;
  136. };
  137. };
  138. /// describe() helper: for most types, report the type as usual
  139. template<typename T>
  140. inline
  141. std::ostream& LLDependencies_describe(std::ostream& out, const T& key)
  142. {
  143. out << key;
  144. return out;
  145. }
  146. /// specialize LLDependencies_describe() for std::string
  147. template<>
  148. inline
  149. std::ostream& LLDependencies_describe(std::ostream& out, const std::string& key)
  150. {
  151. out << '"' << key << '"';
  152. return out;
  153. }
  154. /**
  155. * It's reasonable to use LLDependencies in a keys-only way, more or less like
  156. * std::set. For that case, the default NODE type is an empty struct.
  157. */
  158. struct LLDependenciesEmpty
  159. {
  160. LLDependenciesEmpty() {}
  161. /**
  162. * Give it a constructor accepting void* so caller can pass placeholder
  163. * values such as NULL or 0 rather than having to write
  164. * LLDependenciesEmpty().
  165. */
  166. LLDependenciesEmpty(void*) {}
  167. };
  168. /**
  169. * This class manages abstract dependencies between node types of your
  170. * choosing. As with a std::map, nodes are copied when add()ed, so the node
  171. * type should be relatively lightweight; to manipulate dependencies between
  172. * expensive objects, use a pointer type.
  173. *
  174. * For a given node, you may state the keys of nodes that must precede it
  175. * and/or nodes that must follow it. The sort() method will produce an order
  176. * that should work, or throw an exception if the constraints are impossible.
  177. * We cache results to minimize the cost of repeated sort() calls.
  178. */
  179. template<typename KEY = std::string,
  180. typename NODE = LLDependenciesEmpty>
  181. class LLDependencies: public LLDependenciesBase
  182. {
  183. typedef LLDependencies<KEY, NODE> self_type;
  184. /**
  185. * Internally, we bundle the client's NODE with its before/after keys.
  186. */
  187. struct DepNode
  188. {
  189. typedef std::set<KEY> dep_set;
  190. DepNode(const NODE& node_, const dep_set& after_, const dep_set& before_):
  191. node(node_),
  192. after(after_),
  193. before(before_)
  194. {}
  195. NODE node;
  196. dep_set after, before;
  197. };
  198. typedef std::map<KEY, DepNode> DepNodeMap;
  199. typedef typename DepNodeMap::value_type DepNodeMapEntry;
  200. /// We have various ways to get the dependencies for a given DepNode.
  201. /// Rather than having to restate each one for 'after' and 'before'
  202. /// separately, pass a dep_selector so we can apply each to either.
  203. typedef boost::function<const typename DepNode::dep_set&(const DepNode&)> dep_selector;
  204. public:
  205. LLDependencies() {}
  206. typedef KEY key_type;
  207. typedef NODE node_type;
  208. /// param type used to express lists of other node keys -- note that such
  209. /// lists can be initialized with boost::assign::list_of()
  210. typedef std::vector<KEY> KeyList;
  211. /**
  212. * Add a new node. State its dependencies on other nodes (which may not
  213. * yet have been added) by listing the keys of nodes this new one must
  214. * follow, and separately the keys of nodes this new one must precede.
  215. *
  216. * The node you pass is @em copied into an internal data structure. If you
  217. * want to modify the node value after add()ing it, capture the returned
  218. * NODE& reference.
  219. *
  220. * @note
  221. * Actual dependency analysis is deferred to the sort() method, so
  222. * you can add an arbitrary number of nodes without incurring analysis
  223. * overhead for each. The flip side of this is that add()ing nodes that
  224. * define a cycle leaves this object in a state in which sort() will
  225. * always throw the Cycle exception.
  226. *
  227. * Two distinct use cases are anticipated:
  228. * * The data used to load this object are completely known at compile
  229. * time (e.g. LLEventPump listener names). A Cycle exception represents a
  230. * bug which can be corrected by the coder. The program need neither catch
  231. * Cycle nor attempt to salvage the state of this object.
  232. * * The data are loaded at runtime, therefore the universe of
  233. * dependencies cannot be known at compile time. The client code should
  234. * catch Cycle.
  235. * ** If a Cycle exception indicates fatally-flawed input data, this
  236. * object can simply be discarded, possibly with the entire program run.
  237. * ** If it is essential to restore this object to a working state, the
  238. * simplest workaround is to remove() nodes in LIFO order.
  239. * *** It may be useful to add functionality to this class to track the
  240. * add() chronology, providing a pop() method to remove the most recently
  241. * added node.
  242. * *** It may further be useful to add a restore() method which would
  243. * pop() until sort() no longer throws Cycle. This method would be
  244. * expensive -- but it's not clear that client code could resolve the
  245. * problem more cheaply.
  246. */
  247. NODE& add(const KEY& key, const NODE& node = NODE(),
  248. const KeyList& after = KeyList(),
  249. const KeyList& before = KeyList())
  250. {
  251. // Get the passed-in lists as sets for equality comparison
  252. typename DepNode::dep_set
  253. after_set(after.begin(), after.end()),
  254. before_set(before.begin(), before.end());
  255. // Try to insert the new node; if it already exists, find the old
  256. // node instead.
  257. std::pair<typename DepNodeMap::iterator, bool> inserted =
  258. mNodes.insert(typename DepNodeMap::value_type(key,
  259. DepNode(node, after_set, before_set)));
  260. if (! inserted.second) // bool indicating success of insert()
  261. {
  262. // We already have a node by this name. Have its dependencies
  263. // changed? If the existing node's dependencies are identical, the
  264. // result will be unchanged, so we can leave the cache intact.
  265. // Regardless of inserted.second, inserted.first is the iterator
  266. // to the newly-inserted (or existing) map entry. Of course, that
  267. // entry's second is the DepNode of interest.
  268. if (inserted.first->second.after != after_set ||
  269. inserted.first->second.before != before_set)
  270. {
  271. // Dependencies have changed: clear the cached result.
  272. mCache.clear();
  273. // save the new dependencies
  274. inserted.first->second.after = after_set;
  275. inserted.first->second.before = before_set;
  276. }
  277. }
  278. else // this node is new
  279. {
  280. // This will change results.
  281. mCache.clear();
  282. }
  283. return inserted.first->second.node;
  284. }
  285. /// the value of an iterator, showing both KEY and its NODE
  286. typedef refpair<const KEY&, NODE&> value_type;
  287. /// the value of a const_iterator
  288. typedef refpair<const KEY&, const NODE&> const_value_type;
  289. private:
  290. // Extract functors
  291. static value_type value_extract(DepNodeMapEntry& entry)
  292. {
  293. return value_type(entry.first, entry.second.node);
  294. }
  295. static const_value_type const_value_extract(const DepNodeMapEntry& entry)
  296. {
  297. return const_value_type(entry.first, entry.second.node);
  298. }
  299. // All the iterator access methods return iterator ranges just to cut down
  300. // on the friggin' boilerplate!!
  301. /// generic mNodes range method
  302. template<typename ITERATOR, typename FUNCTION>
  303. boost::iterator_range<ITERATOR> generic_range(FUNCTION function)
  304. {
  305. return make_transform_range(mNodes, function);
  306. }
  307. /// generic mNodes const range method
  308. template<typename ITERATOR, typename FUNCTION>
  309. boost::iterator_range<ITERATOR> generic_range(FUNCTION function) const
  310. {
  311. return make_transform_range(mNodes, function);
  312. }
  313. public:
  314. /// iterator over value_type entries
  315. typedef boost::transform_iterator<boost::function<value_type(DepNodeMapEntry&)>,
  316. typename DepNodeMap::iterator> iterator;
  317. /// range over value_type entries
  318. typedef boost::iterator_range<iterator> range;
  319. /// iterate over value_type <i>in @c KEY order</i> rather than dependency order
  320. range get_range()
  321. {
  322. return generic_range<iterator>(value_extract);
  323. }
  324. /// iterator over const_value_type entries
  325. typedef boost::transform_iterator<boost::function<const_value_type(const DepNodeMapEntry&)>,
  326. typename DepNodeMap::const_iterator> const_iterator;
  327. /// range over const_value_type entries
  328. typedef boost::iterator_range<const_iterator> const_range;
  329. /// iterate over const_value_type <i>in @c KEY order</i> rather than dependency order
  330. const_range get_range() const
  331. {
  332. return generic_range<const_iterator>(const_value_extract);
  333. }
  334. /// iterator over stored NODEs
  335. typedef boost::transform_iterator<boost::function<NODE&(DepNodeMapEntry&)>,
  336. typename DepNodeMap::iterator> node_iterator;
  337. /// range over stored NODEs
  338. typedef boost::iterator_range<node_iterator> node_range;
  339. /// iterate over NODE <i>in @c KEY order</i> rather than dependency order
  340. node_range get_node_range()
  341. {
  342. // First take a DepNodeMapEntry and extract a reference to its
  343. // DepNode, then from that extract a reference to its NODE.
  344. return generic_range<node_iterator>(
  345. boost::bind<NODE&>(&DepNode::node,
  346. boost::bind<DepNode&>(&DepNodeMapEntry::second, _1)));
  347. }
  348. /// const iterator over stored NODEs
  349. typedef boost::transform_iterator<boost::function<const NODE&(const DepNodeMapEntry&)>,
  350. typename DepNodeMap::const_iterator> const_node_iterator;
  351. /// const range over stored NODEs
  352. typedef boost::iterator_range<const_node_iterator> const_node_range;
  353. /// iterate over const NODE <i>in @c KEY order</i> rather than dependency order
  354. const_node_range get_node_range() const
  355. {
  356. // First take a DepNodeMapEntry and extract a reference to its
  357. // DepNode, then from that extract a reference to its NODE.
  358. return generic_range<const_node_iterator>(
  359. boost::bind<const NODE&>(&DepNode::node,
  360. boost::bind<const DepNode&>(&DepNodeMapEntry::second, _1)));
  361. }
  362. /// const iterator over stored KEYs
  363. typedef boost::transform_iterator<boost::function<const KEY&(const DepNodeMapEntry&)>,
  364. typename DepNodeMap::const_iterator> const_key_iterator;
  365. /// const range over stored KEYs
  366. typedef boost::iterator_range<const_key_iterator> const_key_range;
  367. // We don't provide a non-const iterator over KEYs because they should be
  368. // immutable, and in fact our underlying std::map won't give us non-const
  369. // references.
  370. /// iterate over const KEY <i>in @c KEY order</i> rather than dependency order
  371. const_key_range get_key_range() const
  372. {
  373. // From a DepNodeMapEntry, extract a reference to its KEY.
  374. return generic_range<const_key_iterator>(
  375. boost::bind<const KEY&>(&DepNodeMapEntry::first, _1));
  376. }
  377. /**
  378. * Find an existing NODE, or return NULL. We decided to avoid providing a
  379. * method analogous to std::map::find(), for a couple of reasons:
  380. *
  381. * * For a find-by-key, getting back an iterator to the (key, value) pair
  382. * is less than useful, since you already have the key in hand.
  383. * * For a failed request, comparing to end() is problematic. First, we
  384. * provide range accessors, so it's more code to get end(). Second, we
  385. * provide a number of different ranges -- quick, to which one's end()
  386. * should we compare the iterator returned by find()?
  387. *
  388. * The returned pointer is solely to allow expressing the not-found
  389. * condition. LLDependencies still owns the found NODE.
  390. */
  391. const NODE* get(const KEY& key) const
  392. {
  393. typename DepNodeMap::const_iterator found = mNodes.find(key);
  394. if (found != mNodes.end())
  395. {
  396. return &found->second.node;
  397. }
  398. return NULL;
  399. }
  400. /**
  401. * non-const get()
  402. */
  403. NODE* get(const KEY& key)
  404. {
  405. // Use const implementation, then cast away const-ness of return
  406. return const_cast<NODE*>(const_cast<const self_type*>(this)->get(key));
  407. }
  408. /**
  409. * Remove a node with specified key. This operation is the major reason
  410. * we rebuild the graph on the fly instead of storing it.
  411. */
  412. bool remove(const KEY& key)
  413. {
  414. typename DepNodeMap::iterator found = mNodes.find(key);
  415. if (found != mNodes.end())
  416. {
  417. mNodes.erase(found);
  418. return true;
  419. }
  420. return false;
  421. }
  422. private:
  423. /// cached list of iterators
  424. typedef std::vector<iterator> iterator_list;
  425. typedef typename iterator_list::iterator iterator_list_iterator;
  426. public:
  427. /**
  428. * The return type of the sort() method needs some explanation. Provide a
  429. * public typedef to facilitate storing the result.
  430. *
  431. * * We will prepare mCache by looking up DepNodeMap iterators.
  432. * * We want to return a range containing iterators that will walk mCache.
  433. * * If we simply stored DepNodeMap iterators and returned
  434. * (mCache.begin(), mCache.end()), dereferencing each iterator would
  435. * obtain a DepNodeMap iterator.
  436. * * We want the caller to loop over @c value_type: pair<KEY, NODE>.
  437. * * This requires two transformations:
  438. * ** mCache must contain @c LLDependencies::iterator so that
  439. * dereferencing each entry will obtain an @c LLDependencies::value_type
  440. * rather than a DepNodeMapEntry.
  441. * ** We must wrap mCache's iterators in boost::indirect_iterator so that
  442. * dereferencing one of our returned iterators will also dereference the
  443. * iterator contained in mCache.
  444. */
  445. typedef boost::iterator_range<boost::indirect_iterator<iterator_list_iterator> > sorted_range;
  446. /// for convenience in looping over a sorted_range
  447. typedef typename sorted_range::iterator sorted_iterator;
  448. /**
  449. * Once we've loaded in the dependencies of interest, arrange them into an
  450. * order that works -- or throw Cycle exception.
  451. *
  452. * Return an iterator range over (key, node) pairs that traverses them in
  453. * the desired order.
  454. */
  455. sorted_range sort() const
  456. {
  457. // Changes to mNodes cause us to clear our cache, so empty mCache
  458. // means it's invalid and should be recomputed. However, if mNodes is
  459. // also empty, then an empty mCache represents a valid order, so don't
  460. // bother sorting.
  461. if (mCache.empty() && ! mNodes.empty())
  462. {
  463. // Construct a map of node keys to distinct vertex numbers -- even for
  464. // nodes mentioned only in before/after constraints, that haven't yet
  465. // been explicitly added. Rely on std::map rejecting a second attempt
  466. // to insert the same key. Use the map's size() as the vertex number
  467. // to get a distinct value for each successful insertion.
  468. typedef std::map<KEY, int> VertexMap;
  469. VertexMap vmap;
  470. // Nest each of these loops because !@#$%? MSVC warns us that its
  471. // former broken behavior has finally been fixed -- and our builds
  472. // treat warnings as errors.
  473. {
  474. for (typename DepNodeMap::const_iterator nmi = mNodes.begin(), nmend = mNodes.end();
  475. nmi != nmend; ++nmi)
  476. {
  477. vmap.insert(typename VertexMap::value_type(nmi->first, vmap.size()));
  478. for (typename DepNode::dep_set::const_iterator ai = nmi->second.after.begin(),
  479. aend = nmi->second.after.end();
  480. ai != aend; ++ai)
  481. {
  482. vmap.insert(typename VertexMap::value_type(*ai, vmap.size()));
  483. }
  484. for (typename DepNode::dep_set::const_iterator bi = nmi->second.before.begin(),
  485. bend = nmi->second.before.end();
  486. bi != bend; ++bi)
  487. {
  488. vmap.insert(typename VertexMap::value_type(*bi, vmap.size()));
  489. }
  490. }
  491. }
  492. // Define the edges. For this we must traverse mNodes again, mapping
  493. // all the known key dependencies to integer pairs.
  494. EdgeList edges;
  495. {
  496. for (typename DepNodeMap::const_iterator nmi = mNodes.begin(), nmend = mNodes.end();
  497. nmi != nmend; ++nmi)
  498. {
  499. int thisnode = vmap[nmi->first];
  500. // after dependencies: build edges from the named node to this one
  501. for (typename DepNode::dep_set::const_iterator ai = nmi->second.after.begin(),
  502. aend = nmi->second.after.end();
  503. ai != aend; ++ai)
  504. {
  505. edges.push_back(EdgeList::value_type(vmap[*ai], thisnode));
  506. }
  507. // before dependencies: build edges from this node to the
  508. // named one
  509. for (typename DepNode::dep_set::const_iterator bi = nmi->second.before.begin(),
  510. bend = nmi->second.before.end();
  511. bi != bend; ++bi)
  512. {
  513. edges.push_back(EdgeList::value_type(thisnode, vmap[*bi]));
  514. }
  515. }
  516. }
  517. // Hide the gory details of our topological sort, since they shouldn't
  518. // get reinstantiated for each distinct NODE type.
  519. VertexList sorted(topo_sort(vmap.size(), edges));
  520. // Build the reverse of vmap to look up the key for each vertex
  521. // descriptor. vmap contains exactly one entry for each distinct key,
  522. // and we're certain that the associated int values are distinct
  523. // indexes. The fact that they're not in order is irrelevant.
  524. KeyList vkeys(vmap.size());
  525. for (typename VertexMap::const_iterator vmi = vmap.begin(), vmend = vmap.end();
  526. vmi != vmend; ++vmi)
  527. {
  528. vkeys[vmi->second] = vmi->first;
  529. }
  530. // Walk the sorted output list, building the result into mCache so
  531. // we'll have it next time someone asks.
  532. mCache.clear();
  533. for (VertexList::const_iterator svi = sorted.begin(), svend = sorted.end();
  534. svi != svend; ++svi)
  535. {
  536. // We're certain that vkeys[*svi] exists. However, there might not
  537. // yet be a corresponding entry in mNodes.
  538. self_type* non_const_this(const_cast<self_type*>(this));
  539. typename DepNodeMap::iterator found = non_const_this->mNodes.find(vkeys[*svi]);
  540. if (found != non_const_this->mNodes.end())
  541. {
  542. // Make an iterator of appropriate type.
  543. mCache.push_back(iterator(found, value_extract));
  544. }
  545. }
  546. }
  547. // Whether or not we've just recomputed mCache, it should now contain
  548. // the results we want. Return a range of indirect_iterators over it
  549. // so that dereferencing a returned iterator will dereference the
  550. // iterator stored in mCache and directly reference the (key, node)
  551. // pair.
  552. boost::indirect_iterator<iterator_list_iterator>
  553. begin(mCache.begin()),
  554. end(mCache.end());
  555. return sorted_range(begin, end);
  556. }
  557. using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const;
  558. /// Override base-class describe() with actual implementation
  559. virtual std::ostream& describe(std::ostream& out, bool full=true) const
  560. {
  561. typename DepNodeMap::const_iterator dmi(mNodes.begin()), dmend(mNodes.end());
  562. if (dmi != dmend)
  563. {
  564. std::string sep;
  565. describe(out, sep, *dmi, full);
  566. while (++dmi != dmend)
  567. {
  568. describe(out, sep, *dmi, full);
  569. }
  570. }
  571. return out;
  572. }
  573. /// describe() helper: report a DepNodeEntry
  574. static std::ostream& describe(std::ostream& out, std::string& sep,
  575. const DepNodeMapEntry& entry, bool full)
  576. {
  577. // If we were asked for a full report, describe every node regardless
  578. // of whether it has dependencies. If we were asked to suppress
  579. // independent nodes, describe this one if either after or before is
  580. // non-empty.
  581. if (full || (! entry.second.after.empty()) || (! entry.second.before.empty()))
  582. {
  583. out << sep;
  584. sep = "\n";
  585. if (! entry.second.after.empty())
  586. {
  587. out << "after ";
  588. describe(out, entry.second.after);
  589. out << " -> ";
  590. }
  591. LLDependencies_describe(out, entry.first);
  592. if (! entry.second.before.empty())
  593. {
  594. out << " -> before ";
  595. describe(out, entry.second.before);
  596. }
  597. }
  598. return out;
  599. }
  600. /// describe() helper: report a dep_set
  601. static std::ostream& describe(std::ostream& out, const typename DepNode::dep_set& keys)
  602. {
  603. out << '(';
  604. typename DepNode::dep_set::const_iterator ki(keys.begin()), kend(keys.end());
  605. if (ki != kend)
  606. {
  607. LLDependencies_describe(out, *ki);
  608. while (++ki != kend)
  609. {
  610. out << ", ";
  611. LLDependencies_describe(out, *ki);
  612. }
  613. }
  614. out << ')';
  615. return out;
  616. }
  617. /// Iterator over the before/after KEYs on which a given NODE depends
  618. typedef typename DepNode::dep_set::const_iterator dep_iterator;
  619. /// range over the before/after KEYs on which a given NODE depends
  620. typedef boost::iterator_range<dep_iterator> dep_range;
  621. /// dependencies access from key
  622. dep_range get_dep_range_from_key(const KEY& key, const dep_selector& selector) const
  623. {
  624. typename DepNodeMap::const_iterator found = mNodes.find(key);
  625. if (found != mNodes.end())
  626. {
  627. return dep_range(selector(found->second));
  628. }
  629. // We want to return an empty range. On some platforms a default-
  630. // constructed range (e.g. dep_range()) does NOT suffice! The client
  631. // is likely to try to iterate from boost::begin(range) to
  632. // boost::end(range); yet these iterators might not be valid. Instead
  633. // return a range over a valid, empty container.
  634. static const typename DepNode::dep_set empty_deps;
  635. return dep_range(empty_deps.begin(), empty_deps.end());
  636. }
  637. /// dependencies access from any one of our key-order iterators
  638. template<typename ITERATOR>
  639. dep_range get_dep_range_from_xform(const ITERATOR& iterator, const dep_selector& selector) const
  640. {
  641. return dep_range(selector(iterator.base()->second));
  642. }
  643. /// dependencies access from sorted_iterator
  644. dep_range get_dep_range_from_sorted(const sorted_iterator& sortiter,
  645. const dep_selector& selector) const
  646. {
  647. // sorted_iterator is a boost::indirect_iterator wrapping an mCache
  648. // iterator, which we can obtain by sortiter.base(). Deferencing that
  649. // gets us an mCache entry, an 'iterator' -- one of our traversal
  650. // iterators -- on which we can use get_dep_range_from_xform().
  651. return get_dep_range_from_xform(*sortiter.base(), selector);
  652. }
  653. /**
  654. * Get a range over the after KEYs stored for the passed KEY or iterator,
  655. * in <i>arbitrary order.</i> If you pass a nonexistent KEY, returns empty
  656. * range -- same as a KEY with no after KEYs. Detect existence of a KEY
  657. * using get() instead.
  658. */
  659. template<typename KEY_OR_ITER>
  660. dep_range get_after_range(const KEY_OR_ITER& key) const;
  661. /**
  662. * Get a range over the before KEYs stored for the passed KEY or iterator,
  663. * in <i>arbitrary order.</i> If you pass a nonexistent KEY, returns empty
  664. * range -- same as a KEY with no before KEYs. Detect existence of a KEY
  665. * using get() instead.
  666. */
  667. template<typename KEY_OR_ITER>
  668. dep_range get_before_range(const KEY_OR_ITER& key) const;
  669. private:
  670. DepNodeMap mNodes;
  671. mutable iterator_list mCache;
  672. };
  673. /**
  674. * Functor to get a dep_range from a KEY or iterator -- generic case. If the
  675. * passed value isn't one of our iterator specializations, assume it's
  676. * convertible to the KEY type.
  677. */
  678. template<typename KEY_ITER>
  679. struct LLDependencies_dep_range_from
  680. {
  681. template<typename KEY, typename NODE, typename SELECTOR>
  682. typename LLDependencies<KEY, NODE>::dep_range
  683. operator()(const LLDependencies<KEY, NODE>& deps,
  684. const KEY_ITER& key,
  685. const SELECTOR& selector)
  686. {
  687. return deps.get_dep_range_from_key(key, selector);
  688. }
  689. };
  690. /// Specialize LLDependencies_dep_range_from for our key-order iterators
  691. template<typename FUNCTION, typename ITERATOR>
  692. struct LLDependencies_dep_range_from< boost::transform_iterator<FUNCTION, ITERATOR> >
  693. {
  694. template<typename KEY, typename NODE, typename SELECTOR>
  695. typename LLDependencies<KEY, NODE>::dep_range
  696. operator()(const LLDependencies<KEY, NODE>& deps,
  697. const boost::transform_iterator<FUNCTION, ITERATOR>& iter,
  698. const SELECTOR& selector)
  699. {
  700. return deps.get_dep_range_from_xform(iter, selector);
  701. }
  702. };
  703. /// Specialize LLDependencies_dep_range_from for sorted_iterator
  704. template<typename BASEITER>
  705. struct LLDependencies_dep_range_from< boost::indirect_iterator<BASEITER> >
  706. {
  707. template<typename KEY, typename NODE, typename SELECTOR>
  708. typename LLDependencies<KEY, NODE>::dep_range
  709. operator()(const LLDependencies<KEY, NODE>& deps,
  710. const boost::indirect_iterator<BASEITER>& iter,
  711. const SELECTOR& selector)
  712. {
  713. return deps.get_dep_range_from_sorted(iter, selector);
  714. }
  715. };
  716. /// generic get_after_range() implementation
  717. template<typename KEY, typename NODE>
  718. template<typename KEY_OR_ITER>
  719. typename LLDependencies<KEY, NODE>::dep_range
  720. LLDependencies<KEY, NODE>::get_after_range(const KEY_OR_ITER& key_iter) const
  721. {
  722. return LLDependencies_dep_range_from<KEY_OR_ITER>()(
  723. *this,
  724. key_iter,
  725. boost::bind<const typename DepNode::dep_set&>(&DepNode::after, _1));
  726. }
  727. /// generic get_before_range() implementation
  728. template<typename KEY, typename NODE>
  729. template<typename KEY_OR_ITER>
  730. typename LLDependencies<KEY, NODE>::dep_range
  731. LLDependencies<KEY, NODE>::get_before_range(const KEY_OR_ITER& key_iter) const
  732. {
  733. return LLDependencies_dep_range_from<KEY_OR_ITER>()(
  734. *this,
  735. key_iter,
  736. boost::bind<const typename DepNode::dep_set&>(&DepNode::before, _1));
  737. }
  738. #endif /* ! defined(LL_LLDEPENDENCIES_H) */