--- /dev/null
+/* Licensed under LGPLv2+ - see LICENSE file for details */
+#include "config.h"
+
+#include <stdbool.h>
+
+#include <ccan/aga/aga.h>
+#include <ccan/hash/hash.h>
+#include <ccan/htable/htable.h>
+#include <ccan/container_of/container_of.h>
+#include <ccan/tal/tal.h>
+
+#include <ccan/agar/agar.h>
+
+#define HASH_BASE 0
+
+struct agar_node {
+ const void *nr;
+ struct aga_node n;
+};
+
+struct agar_state {
+ struct agar_graph *gr;
+ struct aga_graph g;
+ struct htable nodes;
+};
+
+static size_t agar_node_hash(const struct agar_node *nn)
+{
+ return hash_pointer(nn->nr, HASH_BASE);
+}
+
+static size_t agar_rehash(const void *elem, void *p)
+{
+ return agar_node_hash(elem);
+}
+
+static bool agar_node_cmp(const void *candidate, void *ptr)
+{
+ struct agar_node *nn = (struct agar_node *)candidate;
+
+ return (nn->nr == ptr);
+}
+
+static struct aga_node *nr_to_n(struct agar_state *sr, const void *nr)
+{
+ struct agar_node *nn;
+ size_t hash = hash_pointer(nr, HASH_BASE);
+ bool rc;
+
+ nn = htable_get(&sr->nodes, hash, agar_node_cmp, nr);
+ if (!nn) {
+ nn = tal(sr, struct agar_node);
+ assert(nn);
+
+ nn->nr = nr;
+ aga_node_init(&nn->n);
+
+ rc = htable_add(&sr->nodes, hash, nn);
+ assert(rc);
+ }
+
+ return nn ? &nn->n : NULL;
+}
+
+static const void *n_to_nr(struct agar_state *sr, const struct aga_node *n)
+{
+ struct agar_node *nn = container_of(n, struct agar_node, n);
+
+ return nn->nr;
+}
+
+static int convert_edge_info(const struct aga_graph *g,
+ const struct aga_node *n,
+ const void *e, struct aga_edge_info *ei)
+{
+ struct agar_state *sr = container_of(g, struct agar_state, g);
+ const void *nr = n_to_nr(sr, n);
+ struct agar_edge_info eir;
+ int rc;
+
+ eir.to = NULL;
+
+ rc = sr->gr->edge_info(sr->gr, nr, e, &eir);
+
+ if (eir.to)
+ ei->to = nr_to_n(sr, eir.to);
+ else
+ ei->to = NULL;
+
+ return rc;
+}
+
+static const void *convert_first_edge(const struct aga_graph *g,
+ const struct aga_node *n)
+{
+ struct agar_state *sr = container_of(g, struct agar_state, g);
+ const void *nr = n_to_nr(sr, n);
+
+ return sr->gr->first_edge(sr->gr, nr);
+}
+
+static const void *convert_next_edge(const struct aga_graph *g,
+ const struct aga_node *n,
+ const void *e)
+{
+ struct agar_state *sr = container_of(g, struct agar_state, g);
+ const void *nr = n_to_nr(sr, n);
+
+ return sr->gr->next_edge(sr->gr, nr, e);
+}
+
+void agar_init_graph(struct agar_graph *gr,
+ agar_first_edge_fn first_edge,
+ agar_next_edge_fn next_edge,
+ agar_edge_info_fn edge_info)
+{
+ gr->edge_info = edge_info;
+ gr->first_edge = first_edge;
+ gr->next_edge = next_edge;
+}
+
+int agar_error(struct agar_state *sr)
+{
+ return aga_error(&sr->g);
+}
+
+static void agar_destruct_htable(struct agar_state *sr)
+{
+ htable_clear(&sr->nodes);
+}
+
+static struct agar_state *agar_new(void *ctx, struct agar_graph *gr)
+{
+ struct agar_state *sr = tal(ctx, struct agar_state);
+
+ assert(sr);
+
+ sr->gr = gr;
+ htable_init(&sr->nodes, agar_rehash, NULL);
+ tal_add_destructor(sr, agar_destruct_htable);
+ aga_init_graph(&sr->g, convert_first_edge, convert_next_edge,
+ convert_edge_info);
+
+ return sr;
+}
+
+const void *agar_first_edge(const struct agar_graph *gr, const void *nr)
+{
+ return gr->first_edge(gr, nr);
+}
+
+const void *agar_next_edge(const struct agar_graph *gr,
+ const void *nr, const void *e)
+{
+ if (!e)
+ return NULL;
+ else
+ return gr->next_edge(gr, nr, e);
+}
+
+int agar_edge_info(const struct agar_graph *gr, const void *nr, const void *e,
+ struct agar_edge_info *eir)
+{
+ int rc;
+
+ eir->to = NULL;
+ rc = gr->edge_info(gr, nr, e, eir);
+ assert(rc <= 0);
+ return rc;
+}
+
+/*
+ * Depth first search
+ */
+
+struct agar_dfs_state {
+ struct agar_state sr;
+};
+
+struct agar_state *agar_dfs_new(void *ctx, struct agar_graph *gr)
+{
+ struct agar_state *sr = agar_new(ctx, gr);
+
+ if (aga_dfs_start(&sr->g) < 0) {
+ tal_free(sr);
+ return NULL;
+ }
+
+ return sr;
+}
+
+bool agar_dfs_explore(struct agar_state *sr, const void *nr,
+ const void **nextr)
+{
+ struct aga_node *next;
+
+ next = aga_dfs_explore(&sr->g, nr_to_n(sr, nr));
+ if (!next)
+ return false;
+
+ *nextr = n_to_nr(sr, next);
+ return true;
+}
+
+/*
+ * Breadth first search
+ */
+
+struct agar_state *agar_bfs_new(void *ctx, struct agar_graph *gr)
+{
+ struct agar_state *sr = agar_new(ctx, gr);
+
+ if (aga_bfs_start(&sr->g) < 0) {
+ tal_free(sr);
+ return NULL;
+ }
+
+ return sr;
+}
+
+bool agar_bfs_explore(struct agar_state *sr, const void *nr,
+ const void **nextr)
+{
+ struct aga_node *next;
+
+ next = aga_bfs_explore(&sr->g, nr_to_n(sr, nr));
+ if (!next)
+ return false;
+
+ *nextr = n_to_nr(sr, next);
+ return true;
+}