Source: ../../libproto/spt.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2005 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
// $XORP: xorp/libproto/spt.hh,v 1.3 2005/03/25 02:53:25 pavlin Exp $
#ifndef __LIBPROTO_SPT_HH__
#define __LIBPROTO_SPT_HH__
#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();
/**
* Set the origin node.
*
* @return false if the node doesn't exist, otherwise true.
*/
bool set_origin(A node);
/**
* Add node
*
* @return false if the node already exists, otherwise true.
*/
bool add_node(A node);
/**
* Remove node
*
* @return false if the node doesn't exist or has already been
* removed, otherwise true.
*/
bool remove_node(A node);
/**
* Does this node exist?
*
* @return true if the node exists.
*/
bool exists_node(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(A src, int weight, 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(A src, int weight, 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(A src, int& weight, A dst);
/**
* Remove an edge
*
* @param src source node must exist.
* @param dst destination node must exist
* @return true on success.
*/
bool remove_edge(A src, 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:
/**
* 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(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);
/**
* @return 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.
*/
void 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
// 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.
*/
void 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) :
_cmd(cmd), _node(node), _nexthop(nexthop)
{}
Cmd cmd() const { return _cmd; }
A node() const { return _node; }
A nexthop() const { return _nexthop; }
bool operator==(const RouteCmd& lhs) {
return _cmd == lhs._cmd &&
_node == lhs._node &&
_nexthop == lhs._nexthop;
}
string str() const {
string cmd;
switch(_cmd) {
case ADD:
cmd = "ADD";
break;
case DELETE:
cmd = "DELETE";
break;
case REPLACE:
cmd = "REPLACE";
break;
}
return cmd + " node: " + _node + " nexthop: " + _nexthop;
}
private:
Cmd _cmd;
A _node;
A _nexthop;
};
#endif // __LIBPROTO_SPT_HH__
Generated by: pavlin on possum.icir.org on Wed Apr 13 21:52:51 2005, using kdoc $.