Skip to documentation
SLOP

tiny.smg.traversal

Reference tiny.smg traversal

Defined in tiny.smg.

API (13)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.smgtraversal
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersprivate; no linktools.smg.src.traversalindexSlottraversal.Sourceedges
Static calls · unresolved targets: 0 · external targets: 5.
Called byCallsNo direct callersstorage.contextloadFromReadertraversal.Sourcenode
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate; no linktools.smg.src.traversalindexSlottraversal.Sourceprefix
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callsqueryimpactqueryimpactFromReadertraversalimpact
Static calls · unresolved targets: 3 · external targets: 9.

Source: tools/smg/src/root.zig:36

zig
pub const traversal = @import("traversal.zig");

Source: tools/smg/src/traversal.zig

zig
const std = @import("std");const sql = @import("sql");const smg = @import("root.zig");const graph_mod = smg.graph;const model = smg.model;const storage = smg.storage;const row_bytes_max = @import("context/model.zig").row_bytes_max;pub const Direction = enum { incoming, outgoing };pub const Edge = struct {    source: []const u8,    rel: []const u8,    target: []const u8,};pub const Source = union(enum) {    graph: graph_mod.Graph,    stored: *storage.database.Reader,    pub fn node(self: Source, allocator: std.mem.Allocator, name: []const u8) !?model.Node {        return switch (self) {            .graph => |graph| if (graph_mod.getNode(&graph, name)) |found|                found            else                null,            .stored => |reader| blk: {                const found = storage.context.loadFromReader(                    allocator,                    reader,                    name,                    false,                ) catch |err| switch (err) {                    error.NodeNotFound => break :blk null,                    else => return err,                };                break :blk found.node;            },        };    }    pub fn edges(        self: Source,        _: std.mem.Allocator,        name: []const u8,        direction: Direction,    ) !EdgeIterator {        return switch (self) {            .graph => |graph| .{ .graph = .{                .graph = graph,                .indices = if (direction == .incoming)                    graph_mod.incomingEdges(&graph, name)                else                    graph_mod.outgoingEdges(&graph, name),            } },            .stored => |reader| blk: {                var handle = try reader.catalog.openRelation(                    reader.allocator,                    storage.rows.edges_relation,                );                errdefer handle.deinit();                const index_name = if (direction == .incoming)                    storage.rows.edge_target_index                else                    storage.rows.edge_source_index;                const slot = indexSlot(&handle, index_name) orelse                    return error.StorageIndexMissing;                var scan: sql.index.Scan = undefined;                try handle.relation.lookup(                    &scan,                    reader.allocator,                    slot,                    &.{.{ .text = name }},                );                break :blk .{ .stored = .{ .handle = handle, .scan = scan } };            },        };    }    pub fn prefix(        self: Source,        allocator: std.mem.Allocator,        namespace: []const u8,    ) !NodeIterator {        const prefix_name = try std.fmt.allocPrint(allocator, "{s}.", .{namespace});        const end_name = try std.fmt.allocPrint(allocator, "{s}/", .{namespace});        return switch (self) {            .graph => |graph| .{ .graph = .{                .graph = graph,                .prefix_name = prefix_name,            } },            .stored => |reader| blk: {                var handle = try reader.catalog.openRelation(                    reader.allocator,                    storage.rows.nodes_relation,                );                errdefer handle.deinit();                const slot = indexSlot(&handle, storage.rows.node_name_index) orelse                    return error.StorageIndexMissing;                var scan: sql.index.Scan = undefined;                try handle.relation.indexScan(                    &scan,                    reader.allocator,                    slot,                    &.{.{ .text = prefix_name }},                    &.{.{ .text = end_name }},                );                break :blk .{ .stored = .{ .handle = handle, .scan = scan } };            },        };    }};pub const EdgeIterator = union(enum) {    graph: struct {        graph: graph_mod.Graph,        indices: []const usize,        cursor: usize = 0,    },    stored: struct {        handle: sql.catalog.ReadRelationHandle,        scan: sql.index.Scan,        buffer: [row_bytes_max]u8 = undefined,    },    pub fn deinit(self: *EdgeIterator) void {        switch (self.*) {            .graph => {},            .stored => |*stored| {                stored.scan.deinit();                stored.handle.deinit();            },        }    }    /// The returned strings remain valid until the next call to next.    pub fn next(self: *EdgeIterator) !?Edge {        return switch (self.*) {            .graph => |*graph| blk: {                if (graph.cursor == graph.indices.len) break :blk null;                const edge = graph.graph.edges.items[graph.indices[graph.cursor]];                graph.cursor += 1;                break :blk .{                    .source = edge.source,                    .rel = edge.rel,                    .target = edge.target,                };            },            .stored => |*stored| blk: {                const entry = (try stored.scan.next()) orelse break :blk null;                const bytes = (try stored.handle.relation.getInto(                    entry.rowid,                    &stored.buffer,                )) orelse return error.StorageIndexCorrupt;                break :blk .{                    .source = try storage.rows.edgeSourceView(bytes),                    .rel = try storage.rows.edgeRelView(bytes),                    .target = try storage.rows.edgeTargetView(bytes),                };            },        };    }};pub const NodeIterator = union(enum) {    graph: struct {        graph: graph_mod.Graph,        prefix_name: []const u8,        cursor: usize = 0,    },    stored: struct {        handle: sql.catalog.ReadRelationHandle,        scan: sql.index.Scan,        buffer: [row_bytes_max]u8 = undefined,    },    pub fn deinit(self: *NodeIterator) void {        switch (self.*) {            .graph => {},            .stored => |*stored| {                stored.scan.deinit();                stored.handle.deinit();            },        }    }    pub fn next(self: *NodeIterator, allocator: std.mem.Allocator) !?model.Node {        return switch (self.*) {            .graph => |*graph| blk: {                while (graph.cursor < graph.graph.nodes.items.len) {                    const node = graph.graph.nodes.items[graph.cursor];                    graph.cursor += 1;                    if (std.mem.startsWith(u8, node.name, graph.prefix_name)) break :blk node;                }                break :blk null;            },            .stored => |*stored| blk: {                const entry = (try stored.scan.next()) orelse break :blk null;                const bytes = (try stored.handle.relation.getInto(                    entry.rowid,                    &stored.buffer,                )) orelse return error.StorageIndexCorrupt;                break :blk (try storage.rows.decodeNodeRow(                    allocator,                    entry.rowid,                    bytes,                )).node;            },        };    }};fn indexSlot(handle: *const sql.catalog.ReadRelationHandle, name: []const u8) ?usize {    for (handle.index_definitions, 0..) |definition, slot| {        if (std.mem.eql(u8, definition.name, name)) return slot;    }    return null;}pub fn impact(    allocator: std.mem.Allocator,    source: Source,    name: []const u8,    max_depth: ?usize,    coupling_only: bool,) ![]const []const u8 {    var seen = std.StringHashMap(usize).init(allocator);    var queue: std.ArrayList([]const u8) = .empty;    try seen.put(name, 0);    try queue.append(allocator, name);    var cursor: usize = 0;    while (cursor < queue.items.len) : (cursor += 1) {        const current = queue.items[cursor];        const depth = seen.get(current).?;        if (max_depth != null and depth >= max_depth.?) continue;        var edges = try source.edges(allocator, current, .incoming);        defer edges.deinit();        while (try edges.next()) |edge| {            if (coupling_only and !smg.exports.isCoupling(edge.rel)) continue;            if (seen.contains(edge.source)) continue;            const next = if (source == .stored)                try allocator.dupe(u8, edge.source)            else                edge.source;            try seen.put(next, depth + 1);            try queue.append(allocator, next);        }    }    var out: std.ArrayList([]const u8) = .empty;    var iterator = seen.iterator();    while (iterator.next()) |entry| {        if (!std.mem.eql(u8, entry.key_ptr.*, name)) {            try out.append(allocator, entry.key_ptr.*);        }    }    std.mem.sort([]const u8, out.items, {}, stringLess);    return try out.toOwnedSlice(allocator);}fn stringLess(_: void, left: []const u8, right: []const u8) bool {    return std.mem.lessThan(u8, left, right);}

Audit

Definitions14
Public names14
Members11
Version26.7.0
Revisiondaab053ee433