From e13b09215eacac5f5bda5bbd574c1259a95c823e Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 17 May 2021 21:26:27 +0200 Subject: [PATCH] Add virtual tree graphviz printing methods --- vt.go | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/vt.go b/vt.go index 81a05d0..5970db8 100644 --- a/vt.go +++ b/vt.go @@ -1,8 +1,15 @@ +// Package arbo > vt.go implements the Virtual Tree, which computes a tree +// without computing any hash. With the idea of once all the leafs are placed in +// their positions, the hashes can be computed, avoiding computing a node hash +// more than one time. +//nolint:unused,deadcode package arbo import ( "bytes" + "encoding/hex" "fmt" + "io" ) type node struct { @@ -11,7 +18,7 @@ type node struct { k []byte v []byte path []bool - h []byte + // h []byte } type params struct { @@ -177,3 +184,87 @@ func (n *node) downUntilDivergence(p *params, currLvl int, oldLeaf, newLeaf *nod func (n *node) computeHashes() ([]kv, error) { return nil, nil } + +func (t *vt) graphviz(w io.Writer) error { + fmt.Fprintf(w, `digraph hierarchy { +node [fontname=Monospace,fontsize=10,shape=box] +`) + if _, err := t.root.graphviz(w, t.params, 0); err != nil { + return err + } + fmt.Fprintf(w, "}\n") + return nil +} + +func (n *node) graphviz(w io.Writer, p *params, nEmpties int) (int, error) { + nChars := 4 // TODO move to global constant + if n == nil { + return nEmpties, nil + } + + t := n.typ() + switch t { + case vtLeaf: + leafKey, _, err := newLeafValue(p.hashFunction, n.k, n.v) + if err != nil { + return nEmpties, err + } + fmt.Fprintf(w, "\"%p\" [style=filled,label=\"%v\"];\n", n, hex.EncodeToString(leafKey[:nChars])) + + fmt.Fprintf(w, "\"%p\" -> {\"k:%v\\nv:%v\"}\n", n, + hex.EncodeToString(n.k[:nChars]), + hex.EncodeToString(n.v[:nChars])) + fmt.Fprintf(w, "\"k:%v\\nv:%v\" [style=dashed]\n", + hex.EncodeToString(n.k[:nChars]), + hex.EncodeToString(n.v[:nChars])) + case vtMid: + fmt.Fprintf(w, "\"%p\" [label=\"\"];\n", n) + + lStr := fmt.Sprintf("%p", n.l) + rStr := fmt.Sprintf("%p", n.r) + eStr := "" + if n.l == nil { + lStr = fmt.Sprintf("empty%v", nEmpties) + eStr += fmt.Sprintf("\"%v\" [style=dashed,label=0];\n", + lStr) + nEmpties++ + } + if n.r == nil { + rStr = fmt.Sprintf("empty%v", nEmpties) + eStr += fmt.Sprintf("\"%v\" [style=dashed,label=0];\n", + rStr) + nEmpties++ + } + fmt.Fprintf(w, "\"%p\" -> {\"%v\" \"%v\"}\n", n, lStr, rStr) + fmt.Fprint(w, eStr) + nEmpties, err := n.l.graphviz(w, p, nEmpties) + if err != nil { + return nEmpties, err + } + nEmpties, err = n.r.graphviz(w, p, nEmpties) + if err != nil { + return nEmpties, err + } + + case vtEmpty: + default: + return nEmpties, fmt.Errorf("ERR") + } + + return nEmpties, nil +} + +func (t *vt) printGraphviz() error { + w := bytes.NewBufferString("") + fmt.Fprintf(w, + "--------\nGraphviz:\n") + err := t.graphviz(w) + if err != nil { + fmt.Println(w) + return err + } + fmt.Fprintf(w, + "End of Graphviz --------\n") + fmt.Println(w) + return nil +}