Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 41e5a1f

Browse files
authored
add merkletrie iterator and its helper frame type (#252)
* add merkletrie iterator and its helper frame type * requested changes by mcuadros * reuqested changes: smola
1 parent 8d45daf commit 41e5a1f

File tree

4 files changed

+873
-0
lines changed

4 files changed

+873
-0
lines changed
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package frame
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"sort"
7+
"strings"
8+
9+
"srcd.works/go-git.v4/utils/merkletrie/noder"
10+
)
11+
12+
// A Frame is a collection of siblings in a trie, sorted alphabetically
13+
// by name.
14+
type Frame struct {
15+
// siblings, sorted in reverse alphabetical order by name
16+
stack []noder.Noder
17+
}
18+
19+
type byName []noder.Noder
20+
21+
func (a byName) Len() int { return len(a) }
22+
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
23+
func (a byName) Less(i, j int) bool {
24+
return strings.Compare(a[i].Name(), a[j].Name()) < 0
25+
}
26+
27+
// New returns a frame with the children of the provided node.
28+
func New(n noder.Noder) (*Frame, error) {
29+
children, err := n.Children()
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
sort.Sort(sort.Reverse(byName(children)))
35+
return &Frame{
36+
stack: children,
37+
}, nil
38+
}
39+
40+
// String returns the quoted names of the noders in the frame sorted in
41+
// alphabeticall order by name, surrounded by square brackets and
42+
// separated by comas.
43+
//
44+
// Examples:
45+
// []
46+
// ["a", "b"]
47+
func (f *Frame) String() string {
48+
var buf bytes.Buffer
49+
_ = buf.WriteByte('[')
50+
51+
sep := ""
52+
for i := f.Len() - 1; i >= 0; i-- {
53+
_, _ = buf.WriteString(sep)
54+
sep = ", "
55+
_, _ = buf.WriteString(fmt.Sprintf("%q", f.stack[i].Name()))
56+
}
57+
58+
_ = buf.WriteByte(']')
59+
60+
return buf.String()
61+
}
62+
63+
// First returns, but dont extract, the noder with the alphabetically
64+
// smaller name in the frame and true if the frame was not empy.
65+
// Otherwise it returns nil and false.
66+
func (f *Frame) First() (noder.Noder, bool) {
67+
if f.Len() == 0 {
68+
return nil, false
69+
}
70+
71+
top := f.Len() - 1
72+
73+
return f.stack[top], true
74+
}
75+
76+
// Drop extracts the noder with the alphabetically smaller name in the
77+
// frame or does nothing if the frame was empty.
78+
func (f *Frame) Drop() {
79+
if f.Len() == 0 {
80+
return
81+
}
82+
83+
top := f.Len() - 1
84+
f.stack[top] = nil
85+
f.stack = f.stack[:top]
86+
}
87+
88+
// Len returns the number of noders in the frame.
89+
func (f *Frame) Len() int {
90+
return len(f.stack)
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package frame
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"srcd.works/go-git.v4/utils/merkletrie/internal/fsnoder"
8+
"srcd.works/go-git.v4/utils/merkletrie/noder"
9+
10+
. "gopkg.in/check.v1"
11+
)
12+
13+
func Test(t *testing.T) { TestingT(t) }
14+
15+
type FrameSuite struct{}
16+
17+
var _ = Suite(&FrameSuite{})
18+
19+
func (s *FrameSuite) TestNewFrameFromEmptyDir(c *C) {
20+
A, err := fsnoder.New("A()")
21+
c.Assert(err, IsNil)
22+
23+
frame, err := New(A)
24+
c.Assert(err, IsNil)
25+
26+
expectedString := `[]`
27+
c.Assert(frame.String(), Equals, expectedString)
28+
29+
first, ok := frame.First()
30+
c.Assert(first, IsNil)
31+
c.Assert(ok, Equals, false)
32+
33+
first, ok = frame.First()
34+
c.Assert(first, IsNil)
35+
c.Assert(ok, Equals, false)
36+
37+
l := frame.Len()
38+
c.Assert(l, Equals, 0)
39+
}
40+
41+
func (s *FrameSuite) TestNewFrameFromNonEmpty(c *C) {
42+
// _______A/________
43+
// | / \ |
44+
// x y B/ C/
45+
// |
46+
// z
47+
root, err := fsnoder.New("A(x<> y<> B() C(z<>))")
48+
c.Assert(err, IsNil)
49+
frame, err := New(root)
50+
c.Assert(err, IsNil)
51+
52+
expectedString := `["B", "C", "x", "y"]`
53+
c.Assert(frame.String(), Equals, expectedString)
54+
55+
l := frame.Len()
56+
c.Assert(l, Equals, 4)
57+
58+
checkFirstAndDrop(c, frame, "B", true)
59+
l = frame.Len()
60+
c.Assert(l, Equals, 3)
61+
62+
checkFirstAndDrop(c, frame, "C", true)
63+
l = frame.Len()
64+
c.Assert(l, Equals, 2)
65+
66+
checkFirstAndDrop(c, frame, "x", true)
67+
l = frame.Len()
68+
c.Assert(l, Equals, 1)
69+
70+
checkFirstAndDrop(c, frame, "y", true)
71+
l = frame.Len()
72+
c.Assert(l, Equals, 0)
73+
74+
checkFirstAndDrop(c, frame, "", false)
75+
l = frame.Len()
76+
c.Assert(l, Equals, 0)
77+
78+
checkFirstAndDrop(c, frame, "", false)
79+
}
80+
81+
func checkFirstAndDrop(c *C, f *Frame, expectedNodeName string, expectedOK bool) {
82+
first, ok := f.First()
83+
c.Assert(ok, Equals, expectedOK)
84+
if expectedOK {
85+
c.Assert(first.Name(), Equals, expectedNodeName)
86+
}
87+
88+
f.Drop()
89+
}
90+
91+
// a mock noder that returns error when Children() is called
92+
type errorNoder struct{}
93+
94+
func (e *errorNoder) Hash() []byte { return nil }
95+
func (e *errorNoder) Name() string { return "" }
96+
func (e *errorNoder) String() string { return "" }
97+
func (e *errorNoder) IsDir() bool { return true }
98+
func (e *errorNoder) Children() ([]noder.Noder, error) {
99+
return nil, fmt.Errorf("mock error")
100+
}
101+
func (e *errorNoder) NumChildren() (int, error) {
102+
return 0, fmt.Errorf("mock error")
103+
}
104+
105+
func (s *FrameSuite) TestNewFrameErrors(c *C) {
106+
_, err := New(&errorNoder{})
107+
c.Assert(err, Not(IsNil))
108+
}

0 commit comments

Comments
 (0)