NodeCount
In the following example node count of object graph is calculated. This example does not use cache.
// Create service
IService service = Services.Create(new NodeHandler());
// Get count service
IService<NodeCount, int> countService = service.Cast<NodeCount, int>();
// Create nodes
Node root = new("root"), a = new("a"), b = new("b"), c = new("c");
// Cyclic graph: root->a, a->b, b->c, c->a
root.Edges.Add(a); a.Edges.Add(b); b.Edges.Add(c); c.Edges.Add(a);
// Count number of nodes for each start node
WriteLine(countService.GetRequired(root)); // "4"
WriteLine(countService.GetRequired(a)); // "3"
WriteLine(countService.GetRequired(b)); // "3"
WriteLine(countService.GetRequired(c)); // "3"
Node class has name and forward edges.
public record Node(string name)
{
/// <summary>Forward reference edge</summary>
public List<Node> Edges = new();
}
NodeCount is request to calculate node count.
/// <summary>Request to calculate node count in <paramref name="node"/>.</summary>
public record struct NodeCount(Node node) : IRequestFor<int>, IRequestNotToBeCached
{
public static implicit operator NodeCount(Node node) => new NodeCount(node);
}
NodeTraverse is request to traverse graph on forward edges.
/// <summary>Request to traverse forward edges</summary>
public record struct NodeTraverse(Node node) : IRequestFor<HashSet<Node>>, IRequestNotToBeCached
{
public static implicit operator NodeTraverse(Node node) => new NodeTraverse(node);
}
NodeHandler processes node requests
/// <summary>Handles node requests</summary>
public class NodeHandler : IHandler<NodeCount, int>, IHandler<NodeTraverse, HashSet<Node>>
{
/// <summary>Count nodes</summary>
public void Handle(IQuery<NodeCount, int> query)
{
// Already handled
if (query.Handled()) return;
// Traverse node graph
HashSet<Node> graph = query.Service.GetRequired<NodeTraverse, HashSet<Node>>(query.Request.node, query.CancellationToken, query.Context);
// Assign count
query.Response.SetValue(graph.Count);
}
/// <summary>Traverse node graph</summary>
public void Handle(IQuery<NodeTraverse, HashSet<Node>> query)
{
// Already handled
if (query.Handled()) return;
// Get node
Node node = query.Request.node;
// Visited set
HashSet<Node> visited = new();
// Visit queue
List<Node> queue = new List<Node>();
// Add start node
queue.Add(node);
// Follow forward edges
while (queue.Count > 0)
{
// Get node from queue
Node next = queue[queue.Count - 1];
queue.RemoveAt(queue.Count - 1);
// Already visited
if (!visited.Add(next)) continue;
// Add edges to queue
queue.AddRange(next.Edges);
}
// Assign result
query.Response.SetValue(visited);
}
}
Full Example
Full example
using System.Collections.Generic;
using System.Linq;
using Avalanche.Service;
using static System.Console;
public class example_nodecount
{
public static void Run()
{
{
// <01>
// Create service
IService service = Services.Create(new NodeHandler());
// Get count service
IService<NodeCount, int> countService = service.Cast<NodeCount, int>();
// Create nodes
Node root = new("root"), a = new("a"), b = new("b"), c = new("c");
// Cyclic graph: root->a, a->b, b->c, c->a
root.Edges.Add(a); a.Edges.Add(b); b.Edges.Add(c); c.Edges.Add(a);
// Count number of nodes for each start node
WriteLine(countService.GetRequired(root)); // "4"
WriteLine(countService.GetRequired(a)); // "3"
WriteLine(countService.GetRequired(b)); // "3"
WriteLine(countService.GetRequired(c)); // "3"
// </01>
}
}
// <91>
public record Node(string name)
{
/// <summary>Forward reference edge</summary>
public List<Node> Edges = new();
}
// </91>
// <92>
/// <summary>Request to calculate node count in <paramref name="node"/>.</summary>
public record struct NodeCount(Node node) : IRequestFor<int>, IRequestNotToBeCached
{
public static implicit operator NodeCount(Node node) => new NodeCount(node);
}
// </92>
// <93>
/// <summary>Request to traverse forward edges</summary>
public record struct NodeTraverse(Node node) : IRequestFor<HashSet<Node>>, IRequestNotToBeCached
{
public static implicit operator NodeTraverse(Node node) => new NodeTraverse(node);
}
// </93>
// <94>
/// <summary>Handles node requests</summary>
public class NodeHandler : IHandler<NodeCount, int>, IHandler<NodeTraverse, HashSet<Node>>
{
/// <summary>Count nodes</summary>
public void Handle(IQuery<NodeCount, int> query)
{
// Already handled
if (query.Handled()) return;
// Traverse node graph
HashSet<Node> graph = query.Service.GetRequired<NodeTraverse, HashSet<Node>>(query.Request.node, query.CancellationToken, query.Context);
// Assign count
query.Response.SetValue(graph.Count);
}
/// <summary>Traverse node graph</summary>
public void Handle(IQuery<NodeTraverse, HashSet<Node>> query)
{
// Already handled
if (query.Handled()) return;
// Get node
Node node = query.Request.node;
// Visited set
HashSet<Node> visited = new();
// Visit queue
List<Node> queue = new List<Node>();
// Add start node
queue.Add(node);
// Follow forward edges
while (queue.Count > 0)
{
// Get node from queue
Node next = queue[queue.Count - 1];
queue.RemoveAt(queue.Count - 1);
// Already visited
if (!visited.Add(next)) continue;
// Add edges to queue
queue.AddRange(next.Edges);
}
// Assign result
query.Response.SetValue(visited);
}
}
// </94>
}