| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /* Licensed under LGPLv2+ - see LICENSE file for details */
- #ifndef CCAN_AGA_H
- #define CCAN_AGA_H
- /*
- * Abstract Graph Algorithms
- *
- * This module implements several standard algorithms on "abstract"
- * (directed) graphs. That is to say rather than requiring a specific
- * concrete representation of the graph, user-supplied callbacks allow
- * the graph to be constructed as it is explored.
- *
- *
- * Node representation
- * ===================
- *
- * Graph nodes are represented by 'struct aga_node'
- *
- * - These will often be embedded in a caller-specific structure
- * (calling code can then locate its own structures using
- * container_of)
- *
- * - Nodes are semi-persistent - they MAY be constructed on the fly by
- * the edge_info callback (see below), but MUST then remain in place
- * at least as long as the completion of the current graph
- * algorithm.
- *
- * - Nodes must be initialized with aga_node_init(), either up front,
- * or as they are constructed on the fly.
- *
- * - The contents of the structure should be treated as opaque by the
- * caller.
- *
- *
- * Edge representation
- * ===================
- *
- * Graph edges are reported by three caller supplied functions,
- * 'first_edge', 'next_edge' and 'edge_info'.
- *
- * - Edges are identified by a (void *)
- * - The combination of a graph, a node and this (void *) MUST
- * uniquely identify an edge
- * - Different edges leading from different nodes MAY have the same
- * (void *) identifier
- * - NULL has a special meaning (indicating there are no more edges
- * from a given node).
- * - Otherwise, edge identifiers are treated as opaque by aga
- *
- * - Calling first_edge, followed by next_edge repeatedly must iterate
- * through all the edges leading from node n.
- *
- * - Either first_edge or next_edge may return NULL indicating there
- * are no further edges from this node
- *
- * - edge_info MAY return a negative value in case of error. This
- * will generally abort any aga algorithm which encounters it.
- *
- * - Otherwise edge_info must return 0. Any other return value will
- * cause an abort().
- *
- * - edge_info MAY set ei->to to NULL, indicating a "missing" edge,
- * thus there MAY be more edge identifiers than actual edges from a
- * given node. Otherwise, edge_info MUST fill in the ei->to field
- * with a pointer to the destination node of the given edge
- *
- * - The ei->to field for a returned edge MAY point to an existing
- * struct aga_node, or it MAY have just been allocated by the edge
- * callback itself. If the latter, it MUST have been initialized
- * with aga_node_init() before the edge callback returns.
- *
- * - If a node is contructed by the edge callback, any subsequent
- * reference to that node by the edge callback for *any* node and
- * index MUST use the same pointer.
- *
- * Concurrency
- * ===========
- *
- * - Because the algorithms implemented here keep state in the
- * aga_node structures, only one algorithm can run at a time.
- * Global state for algorithms is stored in the aga_graph structure.
- *
- * - When you start an algorithm (aga_*_start()) the graph is marked
- * as in-use.
- *
- * - Subsequent attempts to start an algorithm will fail;
- * aga_*_start() will return -1.
- *
- * - To release the graph for another algorithm, use aga_finish().
- *
- * - Calling functions associated with one algorithm while another is
- * running has undefined results.
- *
- * Errors
- * ======
- *
- * - Errors may be reported by the edge_info callback, or may be
- * detected internally by algorithms.
- *
- * - Algorithms will generally stop running when they encounter an
- * error; the call which detects the error and subsequent calls will
- * return a "safe", but otherwise meaningless value.
- *
- * - After an error is encountered aga_error() will return a non-zero
- * value. Negative values are reserved for errors reported by the
- * user supplied edge callback. Positive values are reserved for
- * errors detected interally by aga.
- *
- * - Errors are cleared on aga_finish().
- */
- #include "config.h"
- #include <string.h>
- #include <ccan/build_assert/build_assert.h>
- #include <ccan/check_type/check_type.h>
- #include <ccan/lstack/lstack.h>
- #include <ccan/lqueue/lqueue.h>
- struct aga_graph;
- struct aga_node;
- /*
- * Callbacks
- */
- typedef const void *(*aga_first_edge_fn)(const struct aga_graph *g,
- const struct aga_node *n);
- typedef const void *(*aga_next_edge_fn)(const struct aga_graph *g,
- const struct aga_node *n,
- const void *e);
- struct aga_edge_info {
- struct aga_node *to;
- };
- typedef int (*aga_edge_info_fn)(const struct aga_graph *g,
- const struct aga_node *n,
- const void *e, struct aga_edge_info *ei);
- /*
- * Internal data structures
- */
- struct aga_node {
- int sequence;
- union {
- struct {
- struct lstack_link parent;
- const void *edge;
- } dfs;
- struct {
- struct lqueue_link next;
- const void *edge;
- } bfs;
- } u;
- };
- struct aga_graph {
- int sequence;
- int error;
- aga_first_edge_fn first_edge;
- aga_next_edge_fn next_edge;
- aga_edge_info_fn edge_info;
- };
- /*
- * Core functions
- */
- /**
- * aga_init_graph - Initialize a new abstract graph
- * @g: graph structure to initialize
- * @first_edge: first edge callback
- * @next_edge: next edge callback
- * @edge_into: edge info callback
- *
- * Initialize @g to represent an abstract graph defined by the
- * supplied edge callbacks
- */
- void aga_init_graph_(struct aga_graph *g,
- aga_first_edge_fn first_edge,
- aga_next_edge_fn next_edge,
- aga_edge_info_fn edge_info);
- #define aga_init_graph(g_, fefn_, nefn_, eifn_) \
- do { \
- struct aga_node *n_; \
- struct aga_edge_info *ei_; \
- BUILD_ASSERT(check_types_match((fefn_)((g_), n_), \
- (nefn_)((g_), n_, \
- (fefn_)((g_), n_))) \
- == 0); \
- BUILD_ASSERT(check_type((eifn_)((g_), n_, \
- (fefn_)((g_), n_), ei_), \
- int) == 0); \
- aga_init_graph_((g_), (aga_first_edge_fn)(fefn_), \
- (aga_next_edge_fn)(nefn_), \
- (aga_edge_info_fn)(eifn_)); \
- } while (0)
- /**
- * enum aga_error - Error codes for aga routines
- *
- * These error codes are returned by aga_error() for errors detected
- * within aga itself (rather than errors reported by supplied
- * callbacks, which should be negative
- */
- enum aga_error {
- /* No error */
- AGA_ERR_NONE = 0,
- };
- /**
- * aga_error - Determine error state of a graph
- * @g: the graph
- *
- * Returns 0 if the graph is not in an error state, negative values
- * for error states reported by one of the edge callbacks and
- * postitive values for errors detected by aga itself.
- */
- int aga_error(const struct aga_graph *g);
- /**
- * aga_node_init - Initialize a graph node
- * @node: a graph node
- *
- * Initialize @node as a new graph node. This must be called before
- * @node is passed to any aga function, or returned from an edge_info
- * callback (in the ei->to field)
- */
- static inline void aga_node_init(struct aga_node *node)
- {
- memset(node, 0, sizeof(*node));
- }
- /**
- * aga_finish - Finish an aga algorithm
- * @g: graph
- *
- * Wraps up the aga algorithm currently running on @g. This will
- * clear any error conditions. After this is called it is an error to
- * call aga functions on @g apart from aga_*_start() and aga_error.
- */
- void aga_finish(struct aga_graph *g);
- const void *aga_first_edge(const struct aga_graph *g, const struct aga_node *n);
- const void *aga_next_edge(const struct aga_graph *g, const struct aga_node *n,
- const void *e);
- int aga_edge_info(const struct aga_graph *g, const struct aga_node *n,
- const void *e, struct aga_edge_info *ei);
- #define aga_for_each_edge(_e, _g, _n) \
- for ((_e) = aga_first_edge((_g), (_n)); (_e); \
- (_e) = aga_next_edge((_g), (_n), (_e)))
- #define aga_for_each_edge_info(_e, _ei, _err, _g, _n) \
- for ((_err) = 0, (_e) = aga_first_edge((_g), (_n)); \
- (_e) && ((((_err) = aga_edge_info((_g), (_n), (_e), &(_ei)))) == 0); \
- (_e) = aga_next_edge((_g), (_n), (_e))) \
- if ((_ei).to)
- /*
- * Depth first search
- */
- /**
- * aga_dfs_start - Start a depth-first search
- * @g: graph to search
- *
- * Begins the depth-first search algorithm on @g
- */
- int aga_dfs_start(struct aga_graph *g);
- /**
- * aga_dfs_explore - One step of depth-first search
- * @g: graph to search
- * @n: node to start exploration from
- *
- * If @n has not yet been explored since aga_dfs_start(), returns @n.
- * Otherwise returns the next node after @n in depth-first search
- * order. Marks the returned node as explored.
- */
- struct aga_node *aga_dfs_explore(struct aga_graph *g, struct aga_node *n);
- /**
- * aga_dfs - Depth-first search
- * @_n: pointer to current node (output)
- * @_g: graph to search
- * @_start: node to start from
- *
- * Performs a depth first search. The block following this macro is
- * executed with @_n set first to @_start, then to each node reachable
- * from @_start in depth first search order.
- *
- * aga_dfs_start() must be called before this macro is used.
- */
- #define aga_dfs(_n, _g, _start) \
- for ((_n) = (_start); ((_n) = aga_dfs_explore((_g), (_n))) != NULL; )
- /*
- * Breadth first search
- */
- /**
- * aga_bfs_start - Start a breadth-first search
- * @g: graph to search
- *
- * Begins the breadth-first search algorithm on @g
- */
- int aga_bfs_start(struct aga_graph *g);
- /**
- * aga_bfs_explore - One step of breadth-first search
- * @g: graph to search
- * @n: node to start exploration from
- *
- * If @n has not yet been explored since aga_bfs_start(), returns @n.
- * Otherwise returns the next node after @n in breadth-first search
- * order. Marks the returned node as explored.
- */
- struct aga_node *aga_bfs_explore(struct aga_graph *g, struct aga_node *n);
- /**
- * aga_bfs - Breadth-first search
- * @_n: pointer to current node (output)
- * @_g: graph to search
- * @_start: node to start from
- *
- * Performs a breadth first search. The block following this macro is
- * executed with @_n set first to @_start, then to each node reachable
- * from @_start in depth first search order.
- *
- * aga_bfs_start() must be called before this macro is used.
- */
- #define aga_bfs(_n, _g, _start) \
- for ((_n) = (_start) ; ((_n) = aga_bfs_explore((_g), (_n))) != NULL; )
- #endif /* CCAN_AGA_H */
|