Skip to content

Commit f3d324f

Browse files
committed
treesteps: add doc.go
1 parent d373249 commit f3d324f

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

internal/treesteps/doc.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2025 The LevelDB-Go and Pebble Authors. All rights reserved. Use
2+
// of this source code is governed by a BSD-style license that can be found in
3+
// the LICENSE file.
4+
5+
// Package treesteps provides a framework for recording and visualizing
6+
// step-by-step operations on hierarchical data structures.
7+
//
8+
// The package captures the propagation of operations through a tree-like
9+
// structure, recording each intermediate step along with any state changes.
10+
// This is particularly useful for understanding and debugging how operations
11+
// traverse and modify complex hierarchies.
12+
//
13+
// # Basic Usage
14+
//
15+
// To use treesteps, your hierarchical structure must implement the Node
16+
// interface. Each node should provide:
17+
// - A descriptive name
18+
// - Key properties (as key-value pairs)
19+
// - References to child nodes
20+
//
21+
// Recording works as follows:
22+
//
23+
// 1. Start a recording with StartRecording() on the root node
24+
// 2. For each operation on a node, call StartOpf() before and Finishf() after
25+
// 3. Call NodeUpdated() whenever a node's state changes significantly
26+
// 4. Call Finish() to obtain the recorded steps
27+
//
28+
// The result can be rendered as text or exported as a URL to an interactive
29+
// visualization.
30+
//
31+
// # Build Tags
32+
//
33+
// The treesteps functionality is only available when building with the
34+
// 'invariants' tag. Without this tag, all recording operations become no-ops.
35+
// This allows instrumentation to remain in production code without performance
36+
// impact.
37+
//
38+
// # Example
39+
//
40+
// This example demonstrates recording operations on a simple binary tree that
41+
// tracks the sum of values at each node:
42+
//
43+
// type SumTree struct {
44+
// Value int
45+
// Sum int
46+
// Left *SumTree
47+
// Right *SumTree
48+
// }
49+
//
50+
// // TreeStepsNode implements the treesteps.Node interface.
51+
// func (t *SumTree) TreeStepsNode() treesteps.NodeInfo {
52+
// info := treesteps.NodeInfof("node")
53+
// info.AddPropf("value", "%d", t.Value)
54+
// info.AddPropf("sum", "%d", t.Sum)
55+
// info.AddChildren(t.Left, t.Right)
56+
// return info
57+
// }
58+
//
59+
// // UpdateValue sets a new value and propagates the change up the tree.
60+
// func (t *SumTree) UpdateValue(newValue int) {
61+
// op := treesteps.StartOpf(t, "update(%d)", newValue)
62+
// t.Value = newValue
63+
// treesteps.NodeUpdated(t, "value changed")
64+
// t.recomputeSum()
65+
// op.Finishf("done")
66+
// }
67+
//
68+
// func (t *SumTree) recomputeSum() {)
69+
// sum := t.Value
70+
// if t.Left != nil {
71+
// sum += t.Left.Sum
72+
// }
73+
// if t.Right != nil {
74+
// sum += t.Right.Sum
75+
// }
76+
// if sum != t.Sum {
77+
// t.Sum = sum
78+
// treesteps.NodeUpdated(t, "sum updated")
79+
// }
80+
// }
81+
//
82+
// func Example() {
83+
// root := &SumTree{Value: 5}
84+
// root.Left = &SumTree{Value: 3}
85+
// root.Right = &SumTree{Value: 7}
86+
//
87+
// // Start recording
88+
// rec := treesteps.StartRecording(root, "Update value")
89+
//
90+
// // Perform the operation
91+
// root.Left.UpdateValue(10)
92+
//
93+
// // Finish and get the steps
94+
// steps := rec.Finish()
95+
//
96+
// // Print the recorded steps
97+
// fmt.Println(steps.String())
98+
//
99+
// // Or get a URL for visualization
100+
// url := steps.URL()
101+
// fmt.Println("Visualization:", url.String())
102+
// }
103+
//
104+
// # Recording Options
105+
//
106+
// The MaxTreeDepth and MaxOpDepth options can limit the depth of recording,
107+
// which is useful for large or deeply nested structures:
108+
//
109+
// rec := treesteps.StartRecording(root, "operation",
110+
// treesteps.MaxTreeDepth(5),
111+
// treesteps.MaxOpDepth(3),
112+
// )
113+
//
114+
// # Performance Considerations
115+
//
116+
// Check Enabled && IsRecording() before formatting operations:
117+
//
118+
// if treesteps.Enabled && treesteps.IsRecording(node) {
119+
// op := treesteps.StartOpf(node, "expensive operation: %s", expensiveFormat())
120+
// defer op.Finishf("done")
121+
// }
122+
//
123+
// This avoids allocations when no recording is active. It also allows
124+
// statically eliminating code in non-invariants builds.
125+
package treesteps

0 commit comments

Comments
 (0)