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