Source: ../../libproto/spt.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8 sw=4:
// Copyright (c) 2001-2009 XORP, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License, Version
// 2.1, June 1999 as published by the Free Software Foundation.
// Redistribution and/or modification of this program under the terms of
// any other version of the GNU Lesser General Public License is not
// permitted.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
// see the GNU Lesser General Public License, Version 2.1, a copy of
// which can be found in the XORP LICENSE.lgpl file.
//
// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net
// $XORP: xorp/libproto/spt.hh,v 1.24 2009/01/05 18:30:55 jtc Exp $
#ifndef __LIBPROTO_SPT_HH__
#define __LIBPROTO_SPT_HH__
// #define INCREMENTAL_SPT
// #define DEBUG_LOGGING
// #define DEBUG_PRINT_FUNCTION_NAME
#include "libxorp/ref_ptr.hh"
#include "libxorp/c_format.hh"
#include <list>
#include <map>
#include <set>
template <typename A> class Spt;
template <typename A> class Edge;
template <typename A> class Node;
template <typename A> class PriorityQueue;
template <typename A> class RouteCmd;
/**
* Shortest Path Tree
*
* Compute shortest path tree's
*
*/
template <typename A>
class Spt {
public:
// typedef Node<A>::NodeRef NodeRef;
typedef map<A, typename Node<A>::NodeRef> Nodes;
Spt(bool trace = true) : _trace(trace)
{}
~Spt();
/**
* Clear all state from this Spt instance.
*/
void clear();
/**
* Set the origin node.
*
* @return false if the node doesn't exist, otherwise true.
*/
bool set_origin(const A& node);
/**
* Add node
*
* @return false if the node already exists, otherwise true.
*/
bool add_node(const A& node);
/**
* Update node
*
* @return false if the node doesn't exist, otherwise true.
*/
bool update_node(const A& node);
/**
* Remove node
*
* @return false if the node doesn't exist or has already been
* removed, otherwise true.
*/
bool remove_node(const A& node);
/**
* Does this node exist?
*
* @return true if the node exists.
*/
bool exists_node(const A& node);
/**
* Add a new edge.
*
* @param src source node must exist.
* @param weight edge weight.
* @param dst destination node, created if necessary.
* @return true on success.
*/
bool add_edge(const A& src, int weight, const A& dst);
/**
* Update existing edge weight.
*
* @param src source node must exist.
* @param weight new edge weight.
* @param dst destination node must exist
* @return true on success.
*/
bool update_edge_weight(const A& src, int weight, const A& dst);
/**
* Get edge weight.
*
* @param src source node must exist.
* @param weight of this edge returned.
* @param dst destination node must exist
* @return true on success.
*/
bool get_edge_weight(const A& src, int& weight, const A& dst);
/**
* Remove an edge
*
* @param src source node must exist.
* @param dst destination node must exist
* @return true on success.
*/
bool remove_edge(const A& src, const A& dst);
/**
* Compute the tree.
*
* @param routes a list of route adds, deletes and replaces that must be
* performed.
* @return true on success
*/
bool compute(list<RouteCmd<A> >& routes);
/**
* Convert this graph to presentation format.
*
* @return C++ string with the human-readable ASCII representation
* of the graph.
*/
string str() const;
private:
bool _trace; // True of tracing is enabled.
/**
* Dijkstra
*
* @return true on success.
*/
bool dijkstra();
/**
* Incremental SPT.
*
* @return true on success.
*/
bool incremental_spt();
/**
* Find this node.
*/
typename Node<A>::NodeRef find_node(const A& node);
/**
* Remove all the nodes that have been marked for deletion.
*/
void garbage_collect();
typename Node<A>::NodeRef _origin; // Origin node
Nodes _nodes; // Nodes
};
template <typename A>
class Node {
public:
typedef map <A, Edge<A> > adjacency; // Only one edge allowed
// between nodes.
typedef ref_ptr<Node<A> > NodeRef;
Node(A a, bool trace = false);
~Node();
/**
* @return nodename
*/
A nodename();
/**
* Set nodename
* DONT' USE THIS METHOD.
* Changing the nodename could alter the result of the comparison function,
* causing confusion in the spt map.
*
* @return true on success.
*/
bool set_nodename(A nodename);
/**
* Add a new edge.
*
* @return true on success. false if edge already exists.
*/
bool add_edge(NodeRef dst, int weight);
/**
* Update edge weight.
*
* @return true on success, false if the edge doesn't exist.
*/
bool update_edge_weight(NodeRef dst, int weight);
/**
* Get edge weight.
*
* @return true on success, false if the edge doesn't exist.
*/
bool get_edge_weight(NodeRef dst, int& weight);
/**
* Remove an edge
*/
bool remove_edge(NodeRef dst);
/**
* Drop all adjacencies.
* Used to revive invalid nodes.
*/
void drop_adjacencies();
/**
* Remove all edges that point at invalid nodes.
*/
void garbage_collect();
/**
* Set the valid state.
*/
void set_valid(bool p) { _valid = p; }
/**
* @return true if this node is not marked for deletion.
*/
bool valid() { return _valid;}
/**
* Set the tentative state.
*/
void set_tentative(bool p) { _tentative = p; }
/**
* Get the tentative state.
*/
bool tentative() { return _tentative; }
/**
* Invalidate the weights.
*/
void invalidate_weights() { _current._valid = false; }
/**
* Is the current entry valid.
*/
bool valid_weight() { return _current._valid; }
/**
* Set weights.
* Visit all neighbours that are tentative and add this weight.
*
* @param delta_weight to add to this node.
* @param tentative add all updated adjacent nodes to the
* tentative set.
*/
void set_adjacent_weights(NodeRef me, int delta_weight,
PriorityQueue<A>& tentative);
/**
* Set local weight.
* Set the weight on this node if its tentative and less than the
* previous value.
*
* @return true if its accepted.
*/
bool set_local_weight(int weight);
/**
* get local weight.
*
*/
int get_local_weight();
/**
* The first hop to this node.
*/
void set_first_hop(NodeRef n) { _current._first_hop = n; }
/**
* The first hop to this node.
*/
NodeRef get_first_hop() {
XLOG_ASSERT(_current._valid);
return _current._first_hop;
}
/**
* The node before this.
*/
void set_last_hop(NodeRef n) { _current._last_hop = n; }
/**
* The node before this.
*/
NodeRef get_last_hop() {
XLOG_ASSERT(_current._valid);
return _current._last_hop;
}
/**
* Return the difference between this computation and the last.
*
* @param rcmd the new route to this node if it has changed.
* @return true if the node has changed.
*/
bool delta(RouteCmd<A>& rcmd);
/**
* Clear all the references to other nodes as well as possible
* references to ourselves.
*/
void clear() {
_current.clear();
_previous.clear();
_adjacencies.clear();
}
/**
* Pretty print this node with its adjacencies
*/
string pp() const;
/**
* @return C++ string with the human-readable ASCII representation
* of the node.
*/
string str() const;
private:
bool _valid; // True if node is not marked for deletion.
A _nodename; // Node name, external name of this node.
adjacency _adjacencies; // Adjacency list
bool _trace; // True of tracing is enabled.
// private:
// friend class Spt<A>;
bool _tentative; // Intermediate state for Dijkstra.
struct path {
path()
: _valid(false) {}
bool _valid; // Are these entries valid.
NodeRef _first_hop; // On the path to this node, the
// neighbour of the origin.
NodeRef _last_hop; // On the path to this node the
// previous node.
int _path_length; // The sum of all the edge weights.
void clear() {
_first_hop = _last_hop = typename Node<A>::NodeRef();
}
};
path _current; // Current computation.
path _previous; // Previous computation.
};
template <typename A>
class Edge {
public:
Edge() {}
Edge(typename Node<A>::NodeRef dst, int weight) :
_dst(dst), _weight(weight)
{}
string str() const {
return c_format("%s(%d) ", _dst->str().c_str(), _weight);
}
typename Node<A>::NodeRef _dst;
int _weight;
};
/**
* Tentative nodes in a priority queue.
*/
template <typename A>
class PriorityQueue {
public:
/**
* Add or Update the weight of a node.
* @return true if the weight was used.
*/
bool add(typename Node<A>::NodeRef n, int weight);
/**
* Pop the node with lowest weight.
*/
typename Node<A>::NodeRef pop();
bool empty() { return _tentative.empty(); }
private:
template <typename B>
struct lweight {
bool
operator ()(const typename Node<B>::NodeRef& a,
const typename Node<B>::NodeRef& b) const {
int aw = a->get_local_weight();
int bw = b->get_local_weight();
// If the weights match then sort on node names which must
// be unique.
if (aw == bw)
return a.get() < b.get();
return aw < bw;
}
};
typedef set<typename Node<A>::NodeRef, lweight<A> > Tent;
Tent _tentative;
};
/**
* The idealised command to execute.
*/
template <typename A>
class RouteCmd {
public:
enum Cmd {ADD, DELETE, REPLACE};
RouteCmd() {}
RouteCmd(Cmd cmd, A node, A nexthop, A prevhop, int weight = 0,
bool next_hop_changed = false, bool weight_changed = false) :
_cmd(cmd), _node(node), _nexthop(nexthop), _prevhop(prevhop),
_weight(weight),_next_hop_changed(next_hop_changed),
_weight_changed(weight_changed)
{}
Cmd cmd() const { return _cmd; }
const A& node() const { return _node; }
const A& nexthop() const { return _nexthop; }
const A& prevhop() const { return _prevhop; }
int weight() const { return _weight; }
bool next_hop_changed() const { return _next_hop_changed; }
bool weight_changed() const { return _weight_changed; }
bool operator==(const RouteCmd& lhs) {
return _cmd == lhs._cmd &&
_node == lhs._node &&
_nexthop == lhs._nexthop &&
_prevhop == lhs._prevhop &&
_weight == lhs._weight &&
_next_hop_changed == lhs._next_hop_changed &&
_weight_changed == lhs._weight_changed;
}
string c() const {
string cmd;
switch(_cmd) {
case ADD:
cmd = "ADD";
break;
case DELETE:
cmd = "DELETE";
break;
case REPLACE:
cmd = "REPLACE";
break;
}
return cmd;
}
string str() const {
return c() + " node: " + _node.str() +
" nexthop: " + _nexthop.str() +
" prevhop: " + _prevhop.str() +
" weight: " + c_format("%d", _weight) +
" next hop changed: " + bool_c_str(_next_hop_changed) +
" weight changed: " + bool_c_str(_weight_changed);
}
private:
Cmd _cmd;
A _node;
A _nexthop;
A _prevhop;
int _weight;
bool _next_hop_changed;
bool _weight_changed;
};
template <typename A>
Spt<A>::~Spt()
{
clear();
}
template <typename A>
void
Spt<A>::clear()
{
//XLOG_TRACE(_trace, "Clearing spt %p.", this);
// Release the origin node by assigning an empty value to its ref_ptr.
_origin = typename Node<A>::NodeRef();
// Free all node state in the Spt.
// A depth first traversal might be more efficient, but we just want
// to free memory here. Container Nodes knows nothing about the
// degree of each Node.
// Because the last node reference is held in the container we must be
// careful not to introduce another one in this scope by using
// a reference to a Node ref_ptr.
while (! _nodes.empty()) {
typename Nodes::iterator ii;
for (ii = _nodes.begin(); ii != _nodes.end(); ) {
typename Node<A>::NodeRef& rnr = (*ii).second;
//XLOG_ASSERT(! rnr.is_empty());
rnr->clear();
if (rnr.is_only()) {
_nodes.erase(ii++);
} else {
ii++;
}
}
}
}
template <typename A>
bool
Spt<A>::set_origin(const A& node)
{
// Lookup this node. It must exist.
typename Node<A>::NodeRef srcnode = find_node(node);
if (srcnode.is_empty()) {
XLOG_WARNING("Node does not exist %s", Node<A>(node).str().c_str());
return false;
}
_origin = srcnode;
return true;
}
template <typename A>
bool
Spt<A>::add_node(const A& node)
{
// If a valid node already exists return false
typename Node<A>::NodeRef srcnode = find_node(node);
if (!srcnode.is_empty()) {
if (srcnode->valid()) {
XLOG_WARNING("Node already exists %s",
Node<A>(node).str().c_str());
return false;
} else {
// We are going to revive this node so dump its adjacency
// info.
srcnode->drop_adjacencies();
srcnode->set_valid(true);
return true;
}
}
Node<A> *n = new Node<A>(node, _trace);
_nodes[node] = typename Node<A>::NodeRef(n);
//debug_msg("added node %p\n", n);
return true;
}
template <typename A>
bool
Spt<A>::update_node(const A& node)
{
// If a valid node doesn't exist return false
typename Node<A>::NodeRef srcnode = find_node(node);
if (srcnode.is_empty()) {
XLOG_WARNING("Request to update non-existant node %s",
Node<A>(node).str().c_str());
return false;
}
if (!srcnode->valid()) {
XLOG_WARNING("Node is not valid %s", Node<A>(node).str().c_str());
return false;
}
srcnode->set_nodename(node);
return true;
}
template <typename A>
bool
Spt<A>::remove_node(const A& node)
{
// If a valid node doesn't exist return false
typename Node<A>::NodeRef srcnode = find_node(node);
if (srcnode.is_empty()) {
XLOG_WARNING("Request to delete non-existant node %s",
Node<A>(node).str().c_str());
return false;
}
if (!srcnode->valid()) {
XLOG_WARNING("Node already removed %s", Node<A>(node).str().c_str());
return false;
}
srcnode->set_valid(false);
return true;
}
template <typename A>
bool
Spt<A>::exists_node(const A& node)
{
return _nodes.count(node);
}
template <typename A>
bool
Spt<A>::add_edge(const A& src, int weight, const A& dst)
{
// Find the src node it must exist.
typename Node<A>::NodeRef srcnode = find_node(src);
if (srcnode.is_empty()) {
XLOG_WARNING("Node: %s not found", Node<A>(src).str().c_str());
return false;
}
// The dst node doesn't have to exist. If it doesn't exist create it.
typename Node<A>::NodeRef dstnode = find_node(dst);
if (dstnode.is_empty()) {
if (!add_node(dst)) {
XLOG_WARNING("Add node %s failed", Node<A>(dst).str().c_str());
return false;
}
}
dstnode = find_node(dst);
if (dstnode.is_empty()) {
XLOG_WARNING("Node: %s not found", Node<A>(dst).str().c_str());
return false;
}
return srcnode->add_edge(dstnode, weight);
}
template <typename A>
bool
Spt<A>::update_edge_weight(const A& src, int weight, const A& dst)
{
typename Node<A>::NodeRef srcnode = find_node(src);
if (srcnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(src).str().c_str());
return false;
}
typename Node<A>::NodeRef dstnode = find_node(dst);
if (dstnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(dst).str().c_str());
return false;
}
return srcnode->update_edge_weight(dstnode, weight);
}
template <typename A>
bool
Spt<A>::get_edge_weight(const A& src, int& weight, const A& dst)
{
typename Node<A>::NodeRef srcnode = find_node(src);
if (srcnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(src).str().c_str());
return false;
}
typename Node<A>::NodeRef dstnode = find_node(dst);
if (dstnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(dst).str().c_str());
return false;
}
return srcnode->get_edge_weight(dstnode, weight);
}
template <typename A>
bool
Spt<A>::remove_edge(const A& src, const A& dst)
{
typename Node<A>::NodeRef srcnode = find_node(src);
if (srcnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(src).str().c_str());
return false;
}
typename Node<A>::NodeRef dstnode = find_node(dst);
if (dstnode.is_empty()) {
debug_msg("Node: %s not found\n", Node<A>(dst).str().c_str());
return false;
}
return srcnode->remove_edge(dstnode);
}
template <typename A>
bool
Spt<A>::compute(list<RouteCmd<A> >& routes)
{
#ifdef INCREMENTAL_SPT
if (!incremental_spt())
return false;
#else
if (!dijkstra())
return false;
#endif
for(typename Nodes::const_iterator ni = _nodes.begin();
ni != _nodes.end(); ni++) {
// We don't need to know how to reach ourselves.
if (ni->second == _origin)
continue;
RouteCmd<A> rcmd;
if (ni->second->delta(rcmd))
routes.push_back(rcmd);
}
// Remove all the deleted nodes.
garbage_collect();
return true;
}
template <typename A>
string
Spt<A>::str() const
{
string pres;
if (_origin.is_empty()) {
pres = "No origin\n";
} else
pres = "Origin: " + _origin->str() + "\n";
for(typename Nodes::const_iterator ni = _nodes.begin();
ni != _nodes.end(); ni++) {
pres += ni->second->pp() + "\n";
}
return pres;
}
template <typename A>
inline
void
init_dijkstra(const pair<A, typename Node<A>::NodeRef >& p)
{
p.second->set_tentative(true);
p.second->invalidate_weights();
}
template <typename A>
bool
Spt<A>::dijkstra()
{
if (_origin.is_empty()) {
XLOG_WARNING("No origin");
return false;
}
for_each(_nodes.begin(), _nodes.end(), init_dijkstra<A>);
typename Node<A>::NodeRef current = _origin;
_origin->set_tentative(false);
int weight = 0;
// Map of tentative nodes.
PriorityQueue<A> tentative;
for(;;) {
// Set the weight on all the nodes that are adjacent to this one.
current->set_adjacent_weights(current, weight, tentative);
if (tentative.empty())
break;
current = tentative.pop();
XLOG_ASSERT(!current.is_empty());
// Get the weight of this node.
weight = current->get_local_weight();
// Make the node permanent.
current->set_tentative(false);
// Compute the next hop to get to this node.
typename Node<A>::NodeRef prev = current->get_last_hop();
if (prev == _origin)
current->set_first_hop(current);
else
current->set_first_hop(prev->get_first_hop());
debug_msg("Previous: %s\n", prev->str().c_str());
debug_msg("Permanent: %s distance %d next hop %s\n",
current->str().c_str(),
weight,
current->get_first_hop()->str().c_str());
}
return true;
}
template <typename A>
bool
Spt<A>::incremental_spt()
{
XLOG_UNFINISHED();
return true;
}
template <typename A>
typename Node<A>::NodeRef
Spt<A>::find_node(const A& node)
{
typename map<A, typename Node<A>::NodeRef>::iterator i = _nodes.find(node);
if (i != _nodes.end()) {
// debug_msg("Node %s found\n", Node<A>(node).str().c_str());
return (*i).second;
}
// debug_msg("Node %s not found\n", Node<A>(node).str().c_str());
// Node<A> *n = 0;
return typename Node<A>::NodeRef(/*n*/);
}
template <typename A>
Node<A>::Node(A nodename, bool trace)
: _valid(true), _nodename(nodename), _trace(trace)
{
}
template <typename A>
Node<A>::~Node()
{
clear();
}
template <typename A>
A
Node<A>::nodename()
{
return _nodename;
}
template <typename A>
bool
Node<A>::set_nodename(A nodename)
{
_nodename = nodename;
return true;
}
template <typename A>
bool
Node<A>::add_edge(NodeRef dst, int weight)
{
// See if this edge already exists.
typename adjacency::iterator i = _adjacencies.find(dst->nodename());
// If this edge already exists consider this an error.
if (i != _adjacencies.end()) {
debug_msg("Edge from %s to %s exists\n", str().c_str(),
dst->str().c_str());
return false;
}
_adjacencies.insert(make_pair(dst->nodename(), Edge<A>(dst, weight)));
return true;
}
template <typename A>
bool
Node<A>::update_edge_weight(NodeRef dst, int weight)
{
typename adjacency::iterator i = _adjacencies.find(dst->nodename());
// This edge should exist.
if (i == _adjacencies.end()) {
debug_msg("Edge from %s to %s doesn't exists\n", str().c_str(),
dst->str().c_str());
return false;
}
Edge<A> edge = i->second;
edge._weight = weight;
i->second = edge;
return true;
}
template <typename A>
bool
Node<A>::get_edge_weight(NodeRef dst, int& weight)
{
typename adjacency::iterator i = _adjacencies.find(dst->nodename());
// This edge should exist.
if (i == _adjacencies.end()) {
debug_msg("Edge from %s to %s doesn't exists\n", str().c_str(),
dst->str().c_str());
return false;
}
Edge<A> edge = i->second;
weight = edge._weight;
return true;
}
template <typename A>
bool
Node<A>::remove_edge(NodeRef dst)
{
typename adjacency::iterator i = _adjacencies.find(dst->nodename());
if (i == _adjacencies.end()) {
XLOG_WARNING("Edge from %s to %s doesn't exists", str().c_str(),
dst->str().c_str());
return false;
}
_adjacencies.erase(i);
return true;
}
template <typename A>
void
Node<A>::drop_adjacencies()
{
_adjacencies.clear();
}
template <typename A>
void
Node<A>::garbage_collect()
{
typename adjacency::iterator ni;
for(ni = _adjacencies.begin(); ni != _adjacencies.end();) {
NodeRef node = ni->second._dst;
if (!node->valid()) {
// Clear any references that this node may have to itself.
node->clear();
_adjacencies.erase(ni++);
} else {
ni++;
}
}
}
template <typename A>
void
Node<A>::set_adjacent_weights(NodeRef me, int delta_weight,
PriorityQueue<A>& tentative)
{
typename adjacency::iterator i;
for(i = _adjacencies.begin(); i != _adjacencies.end(); i++) {
NodeRef n = i->second._dst;
debug_msg("Node: %s\n", n->str().c_str());
if (n->valid() && n->tentative()) {
// It is critial that the weight of a node is not changed
// while it is in the PriorityQueue.
if (tentative.add(n, delta_weight + i->second._weight))
n->set_last_hop(me);
}
}
}
template <typename A>
bool
Node<A>::set_local_weight(int weight)
{
// If this node is no longer tentative we shouldn't be changing
// its value.
XLOG_ASSERT(_tentative);
bool accepted = false;
// If no valid state exists just set the weight otherwise make
// sure it's less than the value already present.
if (!_current._valid) {
_current._path_length = weight;
_current._valid = true;
accepted = true;
} else {
if (_current._path_length > weight) {
_current._path_length = weight;
accepted = true;
}
}
return accepted;
}
template <typename A>
int
Node<A>::get_local_weight()
{
// debug_msg("Node: %s\n", str().c_str());
// This node must be valid, tentative and its value must be valid.
XLOG_ASSERT(_valid);
XLOG_ASSERT(_tentative);
XLOG_ASSERT(_current._valid);
return _current._path_length;
}
template <typename A>
bool
Node<A>::delta(RouteCmd<A>& rcmd)
{
// Has this node been deleted?
if (!valid()) {
rcmd = RouteCmd<A>(RouteCmd<A>::DELETE,
nodename(), nodename(), nodename());
return true;
}
path p,c;
c = _current;
p = _previous;
_previous = _current;
// It is possible that this node is not reachable.
if (!c._valid) {
XLOG_TRACE(_trace, "Node: %s not reachable", str().c_str());
if (p._valid) {
rcmd = RouteCmd<A>(RouteCmd<A>::DELETE,
nodename(), nodename(), nodename());
return true;
}
return false;
}
// If the previous result is invalid this is a new route.
if (!p._valid) {
XLOG_ASSERT(_current._valid);
rcmd = RouteCmd<A>(RouteCmd<A>::ADD, nodename(),
_current._first_hop->nodename(),
_current._last_hop->nodename(),
_current._path_length);
return true;
}
XLOG_ASSERT(c._valid);
XLOG_ASSERT(p._valid);
// If nothing has changed, nothing to report.
if (c._first_hop == p._first_hop && c._path_length == p._path_length)
return false;
rcmd = RouteCmd<A>(RouteCmd<A>::REPLACE, nodename(),
_current._first_hop->nodename(),
_current._last_hop->nodename(),
_current._path_length,
c._first_hop != p._first_hop,
c._path_length != p._path_length);
return true;
}
template <typename A>
class Pa: public unary_function<pair<A, Edge<A> >, void> {
public:
void operator()(const pair<A, Edge<A> >& p) {
Edge<A> e = p.second;
_result += e.str();
}
string result() const {
return _result;
}
private:
string _result;
};
template <typename A>
string
Node<A>::pp() const
{
string result = str() + ":: ";
result += for_each(_adjacencies.begin(),_adjacencies.end(),
Pa<A>()).result();
return result;
}
template <typename A>
string
Node<A>::str() const
{
return _nodename.str();
}
#if 0
template <>
string
Node<string>::str() const
{
return _nodename;
}
#endif
template <typename A>
inline
void
gc(const pair<A, typename Node<A>::NodeRef >& p)
{
p.second->garbage_collect();
}
template <typename A>
void
Spt<A>::garbage_collect()
{
// Remove all the invalid nodes.
// Use a reference, no need to bump the ref_ptr in this scope.
for(typename Nodes::iterator ni = _nodes.begin(); ni != _nodes.end();) {
typename Node<A>::NodeRef& node = ni->second;
if (!node->valid()) {
_nodes.erase(ni++);
} else {
ni++;
}
}
// Garbage collect all the edges that point at deleted nodes.
for_each(_nodes.begin(), _nodes.end(), gc<A>);
}
template <typename A>
bool
PriorityQueue<A>::add(typename Node<A>::NodeRef n, int weight)
{
// Find this node if its already in set and remove it.
if (n->valid_weight()) {
typename Tent::iterator i = _tentative.find(n);
for(; i != _tentative.end(); i++) {
if ((*i) == n) {
// debug_msg("Erase %s\n", (*i)->str().c_str());
_tentative.erase(i);
break;
}
}
}
bool accepted = n->set_local_weight(weight);
_tentative.insert(n);
return accepted;
// debug_msg("Insert %s\n", n->str().c_str());
}
template <typename A>
typename Node<A>::NodeRef
PriorityQueue<A>::pop()
{
// Find this node if its already in set and remove it.
typename Tent::iterator i = _tentative.begin();
if (i == _tentative.end())
return typename Node<A>::NodeRef();
typename Node<A>::NodeRef n = *i;
_tentative.erase(i);
// debug_msg("Pop %s\n", n->str().c_str());
return n;
}
#endif // __LIBPROTO_SPT_HH__
Generated by: pavlin on kobe.xorp.net on Wed Jan 7 19:10:46 2009, using kdoc 2.0a54+XORP.