diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ab4631 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2023, Kyle Nusbaum + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/avltree.go b/avltree.go new file mode 100644 index 0000000..c7cfb50 --- /dev/null +++ b/avltree.go @@ -0,0 +1,469 @@ +package ion + +import ( + "cmp" + "fmt" + "io" + + "golang.org/x/exp/constraints" +) + +// AVLTree is a tree-based map of keys of type T to values of type U. +// +// AVLTree is immutable, meaning operations performed on it return +// new trees without modifying the old. Because of the immutable nature +// of the structure, the new tree shares most of its memory with the +// original, meaning operations can be performed efficiently without +// needing to reconstruct an entirely new tree for every operation. +type AVLTree[T cmp.Ordered, U any] struct { + height int8 + k T + v U + l *AVLTree[T, U] + r *AVLTree[T, U] +} + +func (t *AVLTree[T, U]) bf() int8 { + if t.r == nil { + if t.l == nil { + return 0 + } else { + return 0 - t.l.height + } + } else { + if t.l == nil { + return t.r.height + } else { + return t.r.height - t.l.height + } + } +} + +func max[T constraints.Ordered](x, y T) T { + if x > y { + return x + } + return y +} + +// Size returns the number of elements present in the tree. +func (t *AVLTree[T, U]) Size() uint64 { + if t == nil { + return 0 + } + return t.l.Size() + t.r.Size() + 1 +} + +// Insert returns a new tree, consisting of the original tree with the +// key/value pair `k`/`v` added to it. +func (t *AVLTree[T, U]) Insert(k T, v U) *AVLTree[T, U] { + if t == nil { + return &AVLTree[T, U]{k: k, v: v, height: 1} + } + + switch { + case t.k < k: + if t.r == nil { + //t.r = &AVLTree{i: i, height: 1} + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: &AVLTree[T, U]{k: k, v: v, height: 1}, + } + if t.l == nil { + t.height = 2 + } + } else { + tr := t.r.Insert(k, v) + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + l: t.l, + r: tr, + } + t.reheight() + } + case t.k > k: + if t.l == nil { + //t.l = &AVLTree{i: i, height: 1} + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + r: t.r, + l: &AVLTree[T, U]{k: k, v: v, height: 1}, + } + if t.r == nil { + t.height = 2 + } + } else { + tl := t.l.Insert(k, v) + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + l: tl, + r: t.r, + } + t.reheight() + } + case t.k == k: + t := &AVLTree[T, U]{ + k: k, + v: v, + height: t.height, + r: t.r, + l: t.l, + } + return t + } + + return t.balance() +} + +func (t *AVLTree[T, U]) removeLargest() (largest, tree *AVLTree[T, U]) { + if t.r != nil { + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + l, newright := t.r.removeLargest() + t.r = newright + t.reheight() + //t.balance() + return l, t.balance() + } + if t.l != nil { + // This is the farthest right node. + // t = largest, remaining tree is t.l + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + ret := t.l + t.l = nil + t.height = 1 + return t, ret + } else { + // This is the farthest right node. + // t = largest, remaining tree is nil. + return t, nil + } +} + +// Delete returns a new tree that does not contain the key `k`, and +// a boolean indicating whether or not an element was removed. +func (t *AVLTree[T, U]) Delete(k T) (*AVLTree[T, U], bool) { + if t == nil { + return nil, false + } + + switch { + case t.k == k: + if t.l != nil { + if t.r != nil { + // We have two kids. + // Replace the local node with the largest of the + // left subtree. + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + largest, tree := t.l.removeLargest() + t.l = tree + t.k = largest.k + t.v = largest.v + t.reheight() + return t.balance(), true + } else { + // We only have a left node. Replace ourselves with the left node. + return t.l, true + } + } else if t.r != nil { + // We only have a right node. Replace ourselves with the right node. + return t.r, true + } else { + return nil, true + } + + case t.k < k: + if t.r == nil { + return t, false + } else { + if tr, ok := t.r.Delete(k); ok { + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + t.r = tr + t.reheight() + return t.balance(), true + } + return t, false + } + case t.k > k: + if t.l == nil { + return t, false + } else { + if tl, ok := t.l.Delete(k); ok { + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + t.l = tl + t.reheight() + return t.balance(), true + } + return t, false + } + } + return t.balance(), true +} + +func (t *AVLTree[T, U]) balance() *AVLTree[T, U] { + bf := t.bf() + switch { + case bf <= -2: + // left child insert - rebalance + zbf := t.l.bf() + if zbf <= 0 { + // left left + return t.right_rotate() + } else if zbf > 0 { + // left right + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l.left_rotate(), + r: t.r, + } + //t.l = t.l.left_rotate() + // TODO: right_rotate throws away t, so we can probably + // avoid allocating t to begin with. + return t.right_rotate() + } + case bf >= 2: + // right child insert - rebalance + zbf := t.r.bf() + if zbf >= 0 { + // right right + return t.left_rotate() + } else if zbf < 0 { + // right left + t = &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r.right_rotate(), + } + //t.r = t.r.right_rotate() + // TODO: left_rotate throws away t, so we can probably + // avoid allocating t to begin with. + return t.left_rotate() + } + } + return t +} + +func (t *AVLTree[T, U]) getNode(k T) *AVLTree[T, U] { + if t == nil { + return nil + } + + switch { + case t.k == k: + return t + case t.k < k: + return t.r.getNode(k) + case t.k > k: + return t.l.getNode(k) + } + panic("Not possible.") +} + +// Get looks up the element in the map associated with `k`. +// It also returns a boolean indicating whether the value was found. +func (t *AVLTree[T, U]) Get(k T) (U, bool) { + if t == nil { + var r U + return r, false + } + + switch { + case t.k == k: + return t.v, true + case t.k < k: + return t.r.Get(k) + case t.k > k: + return t.l.Get(k) + } + panic("Not possible.") +} + +func (t *AVLTree[T, U]) reheight() { + if t.l != nil { + if t.r != nil { + t.height = max(t.l.height, t.r.height) + 1 + } else { + t.height = t.l.height + 1 + } + } else if t.r != nil { + t.height = t.r.height + 1 + } else { + t.height = 1 + } +} + +func (t *AVLTree[T, U]) right_rotate() *AVLTree[T, U] { + if t.l == nil { + // Nothing on the left to + // rotate to the right. + return t + } + + //y := t + //x := t.l + y := &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + x := &AVLTree[T, U]{ + k: t.l.k, + v: t.l.v, + height: t.l.height, + l: t.l.l, + r: t.l.r, + } + + a := t.l.l + b := t.l.r + c := t.r + + x.l = a + x.r = y + y.l = b + y.r = c + + if y.l != nil { + if y.r != nil { + y.height = max(y.l.height, y.r.height) + 1 + } else { + y.height = y.l.height + 1 + } + } else if y.r != nil { + y.height = y.r.height + 1 + } else { + y.height = 1 + } + + // We rotated right, so x.r != nil + if x.l != nil { + x.height = max(x.l.height, x.r.height) + 1 + } else { + x.height = x.r.height + 1 + } + + return x +} + +func (t *AVLTree[T, U]) left_rotate() *AVLTree[T, U] { + if t.r == nil { + // Nothing on the right to + // rotate to the left. + return t + } + + //x := t + //y := t.r + x := &AVLTree[T, U]{ + k: t.k, + v: t.v, + height: t.height, + l: t.l, + r: t.r, + } + y := &AVLTree[T, U]{ + k: t.r.k, + v: t.r.v, + height: t.r.height, + l: t.r.l, + r: t.r.r, + } + + a := t.l + b := t.r.l + c := t.r.r + + y.l = x + y.r = c + x.l = a + x.r = b + + // We rotated left, so y now definitely has a left. + if x.l != nil { + if x.r != nil { + x.height = max(x.l.height, x.r.height) + 1 + } else { + x.height = x.l.height + 1 + } + } else if x.r != nil { + x.height = x.r.height + 1 + } else { + x.height = 1 + } + + if y.r != nil { + y.height = max(y.l.height, y.r.height) + 1 + } else { + y.height = y.l.height + 1 + } + return y +} + +// Dot writes out a graphviz dot formatted directed graph to +// the writer `w`. This can be used with graphviz to visualize +// the tree's internal structure. +func (r *AVLTree[T, U]) Dot(w io.Writer) { + fmt.Fprintf(w, "digraph tree {\n") + r.rdot(w) + fmt.Fprintf(w, "}\n") +} + +func (r *AVLTree[T, U]) rdot(w io.Writer) { + if r == nil { + return + } + + fmt.Fprintf(w, "\t%v.%d;\n", r.k, r.height) + if r.l != nil { + fmt.Fprintf(w, "\t%v.%d -> %v.%d;\n", + r.k, r.height, r.l.k, r.l.height) + } + if r.r != nil { + fmt.Fprintf(w, "\t%v.%d -> %v.%d;\n", + r.k, r.height, r.r.k, r.r.height) + } + r.l.rdot(w) + r.r.rdot(w) +} diff --git a/avltree_test.go b/avltree_test.go new file mode 100644 index 0000000..ef0f3a9 --- /dev/null +++ b/avltree_test.go @@ -0,0 +1,398 @@ +package ion + +import ( + "math/rand" + "os" + "testing" + "time" +) + +func TestAVLInsert(t *testing.T) { + var tr *AVLTree[uint64, uint64] + for i := uint64(0); i <= 5000; i++ { + ntr := tr.Insert(i, i) + if tr.Size() != i { + t.Fatalf("Inserting %d: tree was modified.\n", i) + } + tr = ntr + } + + for i := uint64(0); i <= 5000; i++ { + j, ok := tr.Get(i) + if !ok { + t.Fatalf("Expected to find %d in the tree, but did not.", i) + } + if j != i { + t.Fatalf("Expected j == i, but j == %v", j) + } + } +} + +// func TestAVLC1(t *testing.T) { + +// var tr *AVLTree +// tr1, _ := tr.Insert(1) +// tr2, _ := tr1.Insert(2) +// tr3, _ := tr2.Insert(3) +// tr4, _ := tr3.Insert(4) +// tr5, _ := tr4.Insert(5) + +// tr6, _ := tr5.Delete(1) +// tr7, _ := tr6.Delete(2) +// tr8, _ := tr7.Delete(3) +// tr9, _ := tr8.Delete(4) +// tr10, _ := tr9.Delete(5) + +// tr1.Dot(os.Stdout) +// tr2.Dot(os.Stdout) +// tr3.Dot(os.Stdout) +// tr4.Dot(os.Stdout) +// tr5.Dot(os.Stdout) + +// tr6.Dot(os.Stdout) +// tr7.Dot(os.Stdout) +// tr8.Dot(os.Stdout) +// tr9.Dot(os.Stdout) +// tr10.Dot(os.Stdout) + +// } + +func checkHeight[T Number, U any](t *testing.T, tr *AVLTree[T, U]) *AVLTree[T, U] { + if tr == nil { + return nil + } + if r := checkHeight(t, tr.l); r != nil { + return r + } + if r := checkHeight(t, tr.r); r != nil { + return r + } + + var l, r int8 + + if tr.l != nil { + l = tr.l.height + } + if tr.r != nil { + r = tr.r.height + } + + if l > r { + if tr.height != l+1 { + //t.Fatalf("T: %v, L: %v, R: %v Expected node %d to have height %d, but had %d\n", + // tr, tr.l, tr.r, tr.i, l+1, tr.height) + return tr + } + } else if tr.height != r+1 { + //t.Fatalf("T: %v, L: %v, R: %v Expected node %d to have height %d, but had %d\n", + // tr, tr.l, tr.r, tr.i, r+1, tr.height) + return tr + } + return nil +} + +func checkBalance[T Number, U any](t *testing.T, tr *AVLTree[T, U]) *AVLTree[T, U] { + if tr == nil { + return nil + } + if r := checkBalance(t, tr.l); r != nil { + return r + } + if r := checkBalance(t, tr.r); r != nil { + return r + } + if b := tr.bf(); b >= 2 || b <= -2 { + return tr + } + return nil +} + +func FuzzAVLInsDel(f *testing.F) { + f.Add(make([]byte, 9000)) + // The format of the byte array is a series of elements of 9 bytes: + // [0][1][2][3][4][5][6][7][8] + // Byte 0 % 2 determines if the operation is an insertion or a deletion + // Bytes 1-8 are the 64-bit integer + // Dangling bytes not totalling 9 bytes are excluded. + f.Fuzz(func(t *testing.T, val []byte) { + var tr *AVLTree[uint64, uint64] + ks := make(map[uint64]struct{}) + dels := make(map[uint64]struct{}) + //inss := make(map[uint64]struct{}) + sz := 0 + szd := 0 + for len(val) >= 9 { + del := val[0]%2 == 0 + v := uint64(val[1]) | + (uint64(val[2]) << 8) | + (uint64(val[3]) << 16) | + (uint64(val[4]) << 24) | + (uint64(val[5]) << 32) | + (uint64(val[6]) << 40) | + (uint64(val[7]) << 48) | + (uint64(val[8]) << 56) + val = val[9:] + if _, ok := ks[v]; !ok { + ntr := tr.Insert(v, v) + ks[v] = struct{}{} + sz++ + tr = ntr + if del { + // Store some of the values to delete later. + //dels = append(dels, v) + if _, ok := dels[v]; !ok { + dels[v] = struct{}{} + szd++ + } + } + } + } + + otr := tr + + for k := range dels { + s := tr.Size() + ntr, ok := tr.Delete(k) + if !ok { + t.Fatalf("Expected to delete %d, but failed.", k) + } + tr = ntr + if tr.Size() != s-1 { + t.Fatalf("Wrong size after deleting %d. Expected %d, but got %d\n", + k, s-1, tr.Size()) + } + } + + if tr.Size() != uint64(sz-len(dels)) { + t.Fatalf("Expected tree size to be %d, but was %d\n", + sz-len(dels), tr.Size()) + } + if otr.Size() != uint64(sz) { + t.Fatalf("Original tree lost some elements during delete.\n") + } + }) +} + +func FuzzAVLConsistency(f *testing.F) { + f.Add(make([]byte, 9000)) + // The format of the byte array is a series of elements of 9 bytes: + // [0][1][2][3][4][5][6][7][8] + // Byte 0 % 2 determines if the operation is an insertion or a deletion + // Bytes 1-8 are the 64-bit integer + // Dangling bytes not totalling 9 bytes are excluded. + f.Fuzz(func(t *testing.T, val []byte) { + var tr *AVLTree[uint64, uint64] + for len(val) >= 9 { + insert := val[0]%2 == 0 + v := uint64(val[1]) | + (uint64(val[2]) << 8) | + (uint64(val[3]) << 16) | + (uint64(val[4]) << 24) | + (uint64(val[5]) << 32) | + (uint64(val[6]) << 40) | + (uint64(val[7]) << 48) | + (uint64(val[8]) << 56) + val = val[9:] + + if insert { + tr = tr.Insert(v, v) + } else { + tr, _ = tr.Delete(v) + } + if ftr := checkHeight(t, tr); ftr != nil { + t.Fatalf("Bad height for node %#v\n", ftr) + } + if ftr := checkBalance(t, tr); ftr != nil { + // f, _ := os.Create("after.dot") + // tr.Dot(f) + // f.Close() + if insert { + t.Logf("After insert of %d\n", v) + } else { + t.Logf("After delete of %d\n", v) + } + t.Fatalf("Bad balance for node %v\n", ftr) + } + } + + }) +} + +func TestAVLConsistency(t *testing.T) { + t.Run("rand-insert-delete", func(t *testing.T) { + seed := time.Now().UnixNano() + //seed := int64(1700079657806063024) + //fmt.Printf("SEED: %d\n", seed) + rand := rand.New(rand.NewSource(seed)) + + insert := 0 + del := 0 + var tr *AVLTree[uint64, uint64] + var dels []uint64 + const sz = 100 + for i := 0; i < sz; i++ { + r := rand.Uint64() + if rand.Int()%2 == 0 { + // Store some of the values to delete later. + dels = append(dels, r) + del++ + } + tr = tr.Insert(r, r) + insert++ + } + + if tr.Size() != sz { + t.Fatalf("(Seed %d): Expected tree size to be %d, but was %d\n", seed, sz, tr.Size()) + } + for _, k := range dels { + s := tr.Size() + tr, _ = tr.Delete(k) + if tr.Size() != s-1 { + t.Fatalf("(Seed %d): Wrong size after deleting %d. Expected %d, but got %d\n", seed, k, s-1, tr.Size()) + } + } + + if tr.Size() != uint64(sz-len(dels)) { + t.Fatalf("(Seed %d): Expected tree size to be %d, but was %d\n", seed, sz-len(dels), tr.Size()) + } + }) + + t.Run("height-balance", func(t *testing.T) { + var tr *AVLTree[uint64, uint64] + const sz = 100000 + checkEach := false + + //seed := int64(1700076327895896749) + seed := time.Now().UnixNano() + rand := rand.New(rand.NewSource(seed)) + + //found := 0 + for i := 0; i < sz; i++ { + // Use a smaller integer space to ensure we delete something eventually + r := rand.Uint32() + if rand.Intn(2) == 0 { + tr, _ = tr.Delete(uint64(0)) + if checkEach { + if ftr := checkHeight(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("After delete (%d), T: %v, L: %v, R: %v Expected node %d to have height _, but had %d\n", + r, ftr, ftr.l, ftr.r, ftr.k, ftr.height) + } + if ftr := checkBalance(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("After delete (%d), T: %v, L: %v, R: %v Found a balance factor %d\n", + r, ftr, ftr.l, ftr.r, ftr.bf()) + } + } + } else { + tr = tr.Insert(uint64(r), uint64(r)) + if checkEach { + if ftr := checkHeight(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("After insert (%d), T: %v, L: %v, R: %v Expected node %d to have height _, but had %d\n", + r, ftr, ftr.l, ftr.r, ftr.k, ftr.height) + } + if ftr := checkBalance(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("After insert (%d), T: %v, L: %v, R: %v Found a balance factor %d\n", + r, ftr, ftr.l, ftr.r, ftr.bf()) + } + } + } + + if i%1000 == 0 { + //fmt.Printf("I: %d, Size: %d, Height: %d\n", i, tr.Size(), height(tr)) + if ftr := checkHeight(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("Seed (%d): T: %v, L: %v, R: %v Expected node %d to have height _, but had %d\n", + seed, ftr, ftr.l, ftr.r, ftr.k, ftr.height) + } + if ftr := checkBalance(t, tr); ftr != nil { + ftr.Dot(os.Stdout) + t.Fatalf("Seed (%d): T: %v, L: %v, R: %v Found a balance factor %d\n", + seed, ftr, ftr.l, ftr.r, ftr.bf()) + } + } + + } + }) + +} + +func TestAVLDelete(t *testing.T) { + var tr *AVLTree[uint64, uint64] + for i := uint64(1); i <= 50; i++ { + tr = tr.Insert(i, i) + } + + tr, _ = tr.Delete(10) + + for i := uint64(1); i <= 9; i++ { + j, ok := tr.Get(i) + if !ok { + t.Fatalf("Expected to find %d in the tree, but did not.", i) + } + if j != i { + t.Fatalf("Expected j == i, but j == %v", j) + } + } + j, ok := tr.Get(10) + if ok { + t.Errorf("Expected NOT to find 10 in the tree, but found it.") + } + if j != 0 { + t.Error("Expected j == 0") + } + +} + +// func TestAVLRotate(t *testing.T) { +// a := &AVLTree{i: 1} +// b := &AVLTree{i: 2} +// c := &AVLTree{i: 3} +// x := &AVLTree{i: 9, l: a, r: b} +// y := &AVLTree{i: 10, l: x, r: c} + +// newY := y.right_rotate() +// if newY.i != x.i { +// t.Errorf("Expected x to be new root.\n") +// } +// if x.l.i != a.i { +// t.Errorf("Expected x.l == a\n") +// } +// if x.r.i != y.i { +// t.Errorf("Expected x.r == y\n") +// } +// if y.l.i != b.i { +// t.Errorf("Expected y.l == b\n") +// } +// if y.r.i != c.i { +// t.Errorf("Expected y.r == c\n") +// } + +// newX := newY.left_rotate() +// if newX != y { +// t.Errorf("Expected x to be new root.\n") +// } +// if x.l != a { +// t.Errorf("Expected x.l == a\n") +// } +// if x.r != b { +// t.Errorf("Expected x.r == b\n") +// } +// if y.l != x { +// t.Errorf("Expected y.l == x\n") +// } +// if y.r != c { +// t.Errorf("Expected y.r == c\n") +// } +// } + +func BenchmarkAVLTree(b *testing.B) { + var t *AVLTree[uint64, uint64] + + for i := 0; i < b.N; i++ { + r := rand.Uint64() + t = t.Insert(r, r) + } +} diff --git a/cmd/functional_echo/main.go b/cmd/functional_echo/main.go new file mode 100644 index 0000000..7a421a5 --- /dev/null +++ b/cmd/functional_echo/main.go @@ -0,0 +1,169 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "io" + "log" + "net" + "os" + "os/signal" + "strings" + "sync" + + "github.com/knusbaum/ion" + "github.com/knusbaum/ion/result" +) + +type Pubsub struct { + mu sync.RWMutex + subs []chan string +} + +func (p *Pubsub) Shutdown() { + p.mu.Lock() + defer p.mu.Unlock() + for _, c := range p.subs { + close(c) + } + p.subs = p.subs[:0] +} + +func (p *Pubsub) Subscribe() chan string { + ch := make(chan string) + p.mu.Lock() + defer p.mu.Unlock() + p.subs = append(p.subs, ch) + return ch +} + +func (p *Pubsub) Unsubscribe(ch chan string) { + p.mu.Lock() + defer p.mu.Unlock() + var k int + for i := 0; i < len(p.subs); i++ { + if p.subs[i] == ch { + continue + } + p.subs[k] = p.subs[i] + k++ + } + p.subs = p.subs[:k] +} + +func (p *Pubsub) Publish(s string) { + p.mu.RLock() + defer p.mu.RUnlock() + for _, c := range p.subs { + select { + case c <- s: + default: + } + } +} + +// listen produces a Seq[Result[net.Conn]] of the connections received +// when listening on tcp!addr. +func listen(ctx context.Context, addr string) ion.Seq[result.Res[net.Conn]] { + ln, err := net.Listen("tcp", addr) + if err != nil { + var v *ion.Vec[result.Res[net.Conn]] + v = v.Append(result.Err[net.Conn](err)) + return v + } + log.Printf("Listening on %v", addr) + + go func() { + <-ctx.Done() + ln.Close() + }() + + return ion.StateGen(func() (result.Res[net.Conn], bool) { + conn, err := ln.Accept() + if err != nil { + log.Printf("Failed to accept connection.\n") + return result.Err[net.Conn](err), false + } + return result.Ok[net.Conn](conn), true + }) +} + +// lines reads r and produces a Seq[string] of the text lines contained +// in it. +func lines[T io.Reader](r T) ion.Seq[string] { + b := bufio.NewReader(r) + return ion.StateGen(func() (string, bool) { + s, err := b.ReadString('\n') + if err != nil { + if err != io.EOF { + log.Printf("Error: %v\n", err) + } + var ior io.Reader + ior = r + if cl, ok := ior.(io.ReadCloser); ok { + cl.Close() + } + return "", false + } + return strings.TrimSpace(s), true + }) +} + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + // Sequence of all connections + conns := listen(ctx, "localhost:8181") + + // Map a handler over the seq to handle any error Results + conns = ion.Map(conns, result.Handle[net.Conn](func(err error) { + log.Printf("Failed to listen: %v", err) + })) + + // Map publishers over the conns. For each conn, subscribe to the + // message bus and spawn a goroutine that writes all messages to the conn. + p := &Pubsub{} + var wg sync.WaitGroup + conns = result.Map(conns, func(c net.Conn) net.Conn { + ch := p.Subscribe() + wg.Add(1) + go func() { + defer wg.Done() + defer p.Unsubscribe(ch) + for e := range ch { + _, err := fmt.Fprintf(c, "%s\n", e) + if err != nil { + fmt.Printf("ERROR SENDING: %s\n", err) + return + } + } + }() + return c + }) + + // Map Seq[Result[net.Conn]] -> Seq[Result[Seq[string]]] + // For each successful connection, create a sequence of lines produced by the + // clients on those connections + ls := result.Map(conns, lines) + + go func() { + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt) + <-c + cancel() + }() + + // Iterate over each sequence of lines, starting a goroutine that iterates through + // those lines, publishing them. + ls.Iterate(ion.Always(result.Apply(func(e ion.Seq[string]) { + go e.Iterate(ion.Always(p.Publish)) + }))) + + // We reached the end of the conn seq, meaning the listener has closed. + p.Publish("Server shutting down. Goodbye.") + p.Shutdown() + + // Wait for all the publishers to finish. + wg.Wait() + log.Printf("Shutting down.\n") +} diff --git a/cmd/simple_echo/main.go b/cmd/simple_echo/main.go new file mode 100644 index 0000000..7fb8378 --- /dev/null +++ b/cmd/simple_echo/main.go @@ -0,0 +1,172 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "io" + "log" + "net" + "os" + "os/signal" + "strings" + "sync" + "time" + + "github.com/knusbaum/ion" + "github.com/knusbaum/ion/result" +) + +type Pubsub struct { + mu sync.RWMutex + subs []chan string +} + +func (p *Pubsub) Shutdown() { + p.mu.Lock() + defer p.mu.Unlock() + for _, c := range p.subs { + close(c) + } + p.subs = p.subs[:0] +} + +func (p *Pubsub) Subscribe() chan string { + ch := make(chan string) + p.mu.Lock() + defer p.mu.Unlock() + p.subs = append(p.subs, ch) + return ch +} + +func (p *Pubsub) Unsubscribe(ch chan string) { + p.mu.Lock() + defer p.mu.Unlock() + var k int + for i := 0; i < len(p.subs); i++ { + if p.subs[i] == ch { + continue + } + p.subs[k] = p.subs[i] + k++ + } + p.subs = p.subs[:k] +} + +func (p *Pubsub) Publish(s string) { + p.mu.RLock() + defer p.mu.RUnlock() + for _, c := range p.subs { + select { + case c <- s: + default: + } + } +} + +// listen produces a Seq[Result[net.Conn]] of the connections received +// when listening on tcp!addr. +func listen(ctx context.Context, addr string) ion.Seq[result.Res[net.Conn]] { + ln, err := net.Listen("tcp", addr) + if err != nil { + var v *ion.Vec[result.Res[net.Conn]] + v = v.Append(result.Err[net.Conn](err)) + return v + } + log.Printf("Listening on %v", addr) + + go func() { + <-ctx.Done() + ln.Close() + }() + + return ion.StateGen(func() (result.Res[net.Conn], bool) { + conn, err := ln.Accept() + if err != nil { + log.Printf("Failed to accept connection.\n") + return result.Err[net.Conn](err), false + } + return result.Ok[net.Conn](conn), true + }) +} + +// lines reads r and produces a Seq[string] of the text lines contained +// in it. +func lines[T io.Reader](r T) ion.Seq[string] { + b := bufio.NewReader(r) + return ion.StateGen(func() (string, bool) { + s, err := b.ReadString('\n') + if err != nil { + if err != io.EOF { + log.Printf("Error: %v\n", err) + } + var ior io.Reader + ior = r + if cl, ok := ior.(io.ReadCloser); ok { + cl.Close() + } + return "", false + } + return strings.TrimSpace(s), true + }) +} + +// handleConn handles a connection by subscribing to p and spawning a goroutine +// sending any messages from p to the conn while reading from the conn and publishing +// those messages to p. +// +// If cr does not contain a conn, it logs an error and returns p +func handleConn(p *Pubsub, cr result.Res[net.Conn]) *Pubsub { + if p == nil { + p = &Pubsub{} + } + result.Apply(func(c net.Conn) { + // Start a goroutine iterating all lines on the connection and publishing them. + go lines[net.Conn](c).Iterate(ion.Always(p.Publish)) + // Start a goroutine listening for all published messages and write them to the + // conn. + go func() { + ch := p.Subscribe() + defer p.Unsubscribe(ch) + for m := range ch { + _, err := fmt.Fprintf(c, "%s\n", m) + if err != nil { + return + } + } + }() + })(cr) + return p +} + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + // Conns is a Seq[Result[net.Conn]] + conns := listen(ctx, "localhost:8181") + + // Map a handler over the seq to handle any error Results + conns = ion.Map(conns, result.Handle[net.Conn](func(err error) { + log.Printf("Failed to listen: %v", err) + })) + + go func() { + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt) + <-c + cancel() + }() + + // Fold the connections with handleConn, which will handle connections + // one-by-one, spawning goroutines to do the communications. + p := ion.Fold(conns, handleConn) + + // We reached the end of the conn seq, meaning the listener has closed. + p.Publish("Server shutting down. Goodbye.") + p.Shutdown() + + // Wait for all the publishers to finish. + // wg.Wait() // No waitgroup available. Need to modify the Fold accumulator + // Instead, we'll just wait for a second. + time.Sleep(1 * time.Second) + log.Printf("Shutting down.\n") +} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..8b4f47f --- /dev/null +++ b/doc.go @@ -0,0 +1,16 @@ +// package ion provides basic immutable data structures and functions on them, +// enabling writing Go programs in a functional style. +// +// This includes immutable trees and sequences, Map, Fold, Filter functions +// and a few other things. +// +// Computations such as those done by Map, Filter, and others are made as +// lazy as possible. This means that most of the operations on a Seq[T] are +// not actually executed until one or more elements of that sequence are +// realized with Elem or Iterate. +// +// The main functionality of this package are the functions operating on +// the Seq[T] type. Take a look at type Seq in the index below. +// +// See the programs in cmd/ for examples demonstrating the usage. +package ion diff --git a/example_test.go b/example_test.go new file mode 100644 index 0000000..d73b57a --- /dev/null +++ b/example_test.go @@ -0,0 +1,76 @@ +package ion_test + +import ( + "fmt" + + "github.com/knusbaum/ion" +) + +func ExampleMap() { + + // Create an unbounded list of integers + n := ion.From[int](0, 1) + + // Map the integers to themselves mod 3 + n = ion.Map(n, func(i int) int { + return i % 3 + }) + + // Get the first 10 and print them + n.Take(10).Iterate(func(i int) bool { + fmt.Printf("%d ", i) + return true + }) + + // Output: 0 1 2 0 1 2 0 1 2 0 +} + +func ExampleFilter() { + // Create an unbounded list of natural numbers + n := ion.From[int](1, 1) + + // Filter the even numbers + n = ion.Filter(n, func(i int) bool { + return i%2 == 0 + }) + + // Get the first 10 and print them + n.Take(10).Iterate(func(i int) bool { + fmt.Printf("%d ", i) + return true + }) + + // Output: 2 4 6 8 10 12 14 16 18 20 +} + +func ExampleGenerate() { + // primes is a Seq[int] of prime numbers created by this generator + primes := ion.Generate(func(state []int) (int, []int, bool) { + // Sieve of erasthenes (sort of) + // state is the list of primes followed by the current number + if len(state) == 0 { + return 2, []int{2, 3}, true + } + i := state[len(state)-1] + state = state[:len(state)-1] + outter: + for { + for _, p := range state { + if i%p == 0 { + i += 1 + continue outter + } + } + state = append(state, i, i+1) + return i, state, true + } + }) + + // Grab the first 10 primes and print them + primes.Take(10).Iterate(func(i int) bool { + fmt.Printf("%d ", i) + return true + }) + + // Output: 2 3 5 7 11 13 17 19 23 29 +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ba76830 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/knusbaum/ion + +go 1.21.3 + +require ( + github.com/knusbaum/gunk v0.1.2 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e552268 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/knusbaum/gunk v0.1.2 h1:EqqlAKx3I84+R+cpKYVa3rDyPqMaSJj3q+X6F372gn8= +github.com/knusbaum/gunk v0.1.2/go.mod h1:hfQh94hYwhDOfGewYFu5Rw5O3Oh1xQ00bUchDDN5syI= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= diff --git a/map.go b/map.go new file mode 100644 index 0000000..951eea6 --- /dev/null +++ b/map.go @@ -0,0 +1,681 @@ +package ion + +import ( + "math" + + "golang.org/x/exp/constraints" +) + +// A Seq is a possibly unbounded sequence of elements of type T. +// Seqs are immutable, so any operation modifying a Seq +// (such as Split) must leave the original Seq intact and return +// two new Seqs. +// +// Many operations on Seqs are lazy in nature, such as mapping +// and filtering, meaning it's possible (and useful) to map +// and filter unbounded sequences. +type Seq[T any] interface { + // Elem returns the element at index i. + // If the sequence does not contain i elements, it will return + // the zero value of T and false. + Elem(i uint64) (T, bool) + + // Split splits a sequence after n elements, returning a Seq + // containing the first n elements and one containing the + // remainder of the original Seq. Split must not modify the + // original Seq. If the seq contains < n elements, the + // first returned sequence will contain all elements from + // the original sequence and the second returned sequence + // will be empty. + // + // Note: the first returned sequence may contain < n elements, + // if the original sequence contained < n elements. + Split(n uint64) (Seq[T], Seq[T]) + + // Take returns a Seq containing the first n elements of the + // original Seq. The original Seq is not modified. + // Take can be more efficient than Split since there are + // more scenarios where evaluation of the Seq elements + // can be delayed. + Take(n uint64) Seq[T] + + // Iterate executes a function over every element of the Seq, + // until the Seq ends or the function returns false. + Iterate(func(T) bool) + + // Lazy executes a function over every element of the Seq, + // passing the elements as thunks which will return the + // element. + // + // This is useful to delay the execution of computations + // such as maps until the execution of the thunk. For instance, + // this can be used to distribute work over a set of goroutines + // and have the goroutines themselves incur the cost of mapping + // the elements is parallel, rather than having the routine + // executing Lazy incuring the cost as is the case with Iterate. + Lazy(func(func() T) bool) +} + +type mappedSeq[T, U any] struct { + s Seq[T] + f func(T) U +} + +func (m *mappedSeq[T, U]) Elem(i uint64) (U, bool) { + if e, ok := m.s.Elem(i); ok { + return m.f(e), true + } + var r U + return r, false +} + +func (m *mappedSeq[T, U]) Split(n uint64) (Seq[U], Seq[U]) { + sl, sr := m.s.Split(n) + l := &mappedSeq[T, U]{ + s: sl, + f: m.f, + } + r := &mappedSeq[T, U]{ + s: sr, + f: m.f, + } + return l, r +} + +func (m *mappedSeq[T, U]) Take(n uint64) Seq[U] { + l := &mappedSeq[T, U]{ + s: m.s.Take(n), + f: m.f, + } + return l +} + +func (m *mappedSeq[T, U]) Iterate(f func(U) bool) { + m.s.Iterate(func(e T) bool { + return f(m.f(e)) + }) +} + +func (m *mappedSeq[T, U]) Lazy(f func(func() U) bool) { + m.s.Lazy(func(e func() T) bool { + return f(func() U { + return m.f(e()) + }) + }) +} + +// Map takes a Seq[T] `s` and a func `f` which will be executed +// on every element of `s`, returning a new value of type U. +// It returns a new Seq[U] containing the results of the map. +// +// The mapping is executed lazily, meaning it is safe and useful +// to Map over unbounded sequences. +// +// For example: +// +// // Create an unbounded list of integers. +// n := From[int](0,1) +// // Map the integers by adding 1 and converting to float64, into an unbounded Seq[float64]. +// m := Map(n, func(i int) float64 { return float64(i) + 1 }) +// +// Values resulting from the application of `f` to the underlying Seq +// are not retained, and `f` may be called multiple times on a given element. +// This being the case, `f` should ideally be idempotent and stateless. +// If it is not, it may not be safe to Iterate the resulting Seq more than once. +// +// Notes about State: +// +// Although it is ideal to use idempotent functions, it is often very useful to +// iterate stateful functions over stateful values, for instance Map'ing a handler +// function over a sequence of connections (say, net.Conn). In these cases, it is +// important not to "realize" elements of the Seq more than once. The simplest +// and fool-proof way to do this is to never apply more than one operation to +// a seq. e.g. this is ok: +// +// var conns Seq[net.Conn] +// conns = listen() +// n := Map(conns, handle) +// e := Fold(n, handleErrors) +// +// But this bay be problematic, because we are applying multiple operations to n: +// +// var conns Seq[net.Conn] +// conns = listen() +// n := Map(conns, handle) +// e := Fold(n, handleErrors) +// other := n.Iterate(func(e SomeType) { +// ... +// }) +// +// The Memo function may be useful in ensuring Map functions are never applied more +// than once to the elements of their underlying Seqs, but keep in mind this means +// the values of these operations are retained in memory. +func Map[T, U any](s Seq[T], f func(T) U) Seq[U] { + return &mappedSeq[T, U]{ + s: s, + f: f, + } +} + +type repseq[T any] struct { + e T + limit uint64 +} + +func (r *repseq[T]) Elem(i uint64) (T, bool) { + return r.e, true +} + +func (r *repseq[T]) Split(n uint64) (Seq[T], Seq[T]) { + s := &repseq[T]{ + e: r.e, + limit: n, + } + + if r.limit > 0 { + if n == r.limit { + return s, (*Vec[T])(nil) + } + return s, &repseq[T]{ + e: r.e, + limit: r.limit - n, + } + } + + return s, r +} + +func (r *repseq[T]) Take(n uint64) Seq[T] { + return &repseq[T]{ + e: r.e, + limit: n, + } +} + +func (r *repseq[T]) Iterate(f func(T) bool) { + if r.limit > 0 { + for i := uint64(0); i < r.limit; i++ { + if !f(r.e) { + return + } + } + return + } else { + for { + if !f(r.e) { + return + } + } + } +} + +func (r *repseq[T]) Lazy(f func(func() T) bool) { + if r.limit > 0 { + for i := uint64(0); i < r.limit; i++ { + if !f(func() T { return r.e }) { + return + } + } + return + } else { + for { + if !f(func() T { return r.e }) { + return + } + } + } + + for { + if !f(func() T { return r.e }) { + return + } + } +} + +// Repeatedly returns an unbounded Seq[T] containing e. +// +// Note, e is copied, so it is wise to use non-pointer or +// immutable values. +func Repeatedly[T any](e T) Seq[T] { + return &repseq[T]{ + e: e, + } +} + +type Number interface { + constraints.Integer | constraints.Float +} + +type genseq[T Number] struct { + start T + by T + limit uint64 +} + +func (r *genseq[T]) Elem(i uint64) (T, bool) { + if r.limit > 0 && i >= r.limit { + var ret T + return ret, false + } + return r.start + T(i)*r.by, true +} + +func (r *genseq[T]) Split(n uint64) (Seq[T], Seq[T]) { + if r.limit > 0 && n > r.limit { + return r, (*Vec[T])(nil) + } + s := &genseq[T]{ + start: r.start, + by: r.by, + limit: n, + } + + e, ok := r.Elem(n) + if !ok { + return r, (*Vec[T])(nil) + } + nr := &genseq[T]{ + start: e, + by: r.by, + limit: r.limit - n, + } + return s, nr +} + +func (r *genseq[T]) Take(n uint64) Seq[T] { + lim := n + if r.limit > 0 && r.limit < n { + lim = r.limit + } + return &genseq[T]{ + start: r.start, + by: r.by, + limit: lim, + } +} + +func (r *genseq[T]) Iterate(f func(T) bool) { + limit := uint64(math.MaxUint64) + if r.limit > 0 { + limit = r.limit + } + for i := uint64(0); i < limit; i++ { + e, _ := r.Elem(i) + if !f(e) { + return + } + } +} + +func (r *genseq[T]) Lazy(f func(func() T) bool) { + limit := uint64(math.MaxUint64) + if r.limit > 0 { + limit = r.limit + } + for i := uint64(0); i < limit; i++ { + j := i + cont := f(func() T { + e, _ := r.Elem(j) + return e + }) + if !cont { + return + } + } +} + +// From creates an unbounded Seq[T] of numeric values (see Number) +// starting at start and increasing by `by`. +func From[T Number](start, by T) Seq[T] { + return &genseq[T]{ + start: start, + by: by, + } +} + +type generateSeq[T, U any] struct { + f func(state U) (T, U, bool) + state U + limit uint64 +} + +// Generate takes a func `f` and executes it in order to generate +// values of type T in the resulting Seq[T]. +// +// The func `f` takes a state of any type, and should generate a +// value based on that state. `f` should be idempotent, as it may +// be executed multiple times on the same state. The func `f` +// must return a value of type T, and the next state of type U. +func Generate[T, U any](f func(state U) (T, U, bool)) Seq[T] { + return &generateSeq[T, U]{ + f: f, + } +} + +func GenerateInit[T, U any](state U, f func(state U) (T, U, bool)) Seq[T] { + return &generateSeq[T, U]{ + f: f, + state: state, + } +} + +func (g *generateSeq[T, U]) Elem(i uint64) (T, bool) { + if g.limit > 0 && i >= g.limit { + var ret T + return ret, false + } + var res T + state := g.state + for j := uint64(0); j <= i; j++ { + var cont bool + res, state, cont = g.f(state) + if !cont { + return res, false + } + } + return res, true +} + +func (g *generateSeq[T, U]) Split(n uint64) (Seq[T], Seq[T]) { + if g.limit > 0 && n > g.limit { + return g, (*Vec[T])(nil) + } + + state := g.state + l := BuildVec(func(add func(T)) { + for i := uint64(0); i < n; i++ { + var e T + var cont bool + e, state, cont = g.f(state) + if !cont { + return + } + add(e) + } + }) + + r := &generateSeq[T, U]{ + f: g.f, + state: state, + limit: g.limit - n, + } + return l, r +} + +func (g *generateSeq[T, U]) Take(n uint64) Seq[T] { + lim := n + if g.limit > 0 && g.limit < n { + lim = g.limit + } + + return &generateSeq[T, U]{ + f: g.f, + state: g.state, + limit: lim, + } +} + +func (g *generateSeq[T, U]) Iterate(f func(T) bool) { + state := g.state + if g.limit > 0 { + var i uint64 + for { + var e T + var cont bool + if i == g.limit { + return + } + i++ + e, state, cont = g.f(state) + if !cont { + return + } + if !f(e) { + return + } + } + } else { + for { + var e T + var cont bool + e, state, cont = g.f(state) + if !cont { + return + } + if !f(e) { + return + } + } + } +} + +func (g *generateSeq[T, U]) Lazy(f func(func() T) bool) { + // unfortunately this cannot be lazy, because Elem(i) depends on + // elem i-1, and we cannot guarantee the execution order of the + // thunks we return. Instead, we evaluate the current element and + // return a closure that returns it. + state := g.state + if g.limit > 0 { + var i uint64 + for { + var e T + var cont bool + if i == g.limit { + return + } + i++ + e, state, cont = g.f(state) + if !cont { + return + } + if !f(func() T { return e }) { + return + } + } + } else { + for { + var e T + var cont bool + e, state, cont = g.f(state) + if !cont { + return + } + if !f(func() T { return e }) { + return + } + } + } +} + +// Fold folds a Seq[T] `s` into a value of type U, based on the function `f`. +// The function `f` is run over each element of `s`. It accepts a value of +// type U, which is the current value (accumulator) for the fold, and a +// value of type T, which is the current element of `s`. The function `f` +// must return the new accumulator value of type U. Fold returns the final +// accumulator value after `f` has been run over every element of `s`. +// +// Note: Running a fold on an unbounded sequence will never terminate. +// One should usually use Split() or Fold() on unbounded sequences first +// to limit the output. +// +// For example, to sum the first 1000 primes (with imaginary isPrime and sum +// functions): +// +// n := From[int](1,1) +// n = Filter(n, isPrime) +// n = n.Take(1000) +// result := Fold(n, sum) +// +// Or more succinctly: +// +// result := Fold(Filter(From[int](1,1), isPrime).Take(1000), sum) +func Fold[T, U any](s Seq[T], f func(U, T) U) U { + var u U + var i uint64 + s.Iterate(func(e T) bool { + i++ + u = f(u, e) + return true + }) + return u +} + +type filterSeq[T any] struct { + s Seq[T] + f func(T) bool + limit uint64 +} + +func (f *filterSeq[T]) Elem(i uint64) (T, bool) { + if f.limit > 0 && i >= f.limit { + var ret T + return ret, false + } + var res T + var ec uint64 + var found bool + f.s.Iterate(func(e T) bool { + if f.f(e) { + if ec == i { + res = e + found = true + return false + } + ec++ + } + return true + }) + return res, found +} + +func (f *filterSeq[T]) Split(n uint64) (Seq[T], Seq[T]) { + if f.limit > 0 && n > f.limit { + return f, (*Vec[T])(nil) + } + + var i uint64 + var split uint64 + l := BuildVec(func(add func(T)) { + f.s.Iterate(func(e T) bool { + if i == n { + return false + } + split++ + if f.f(e) { + add(e) + i++ + } + return true + }) + }) + _, rr := f.s.Split(split) + r := &filterSeq[T]{ + s: rr, + f: f.f, + limit: f.limit - n, + } + return l, r +} + +func (f *filterSeq[T]) Take(n uint64) Seq[T] { + lim := n + if f.limit > 0 && f.limit < n { + lim = f.limit + } + return &filterSeq[T]{ + s: f.s, + f: f.f, + limit: lim, + } +} + +func (f *filterSeq[T]) Iterate(fn func(T) bool) { + if f.limit > 0 { + var i uint64 + f.s.Iterate(func(e T) bool { + if i == f.limit { + return false + } + if f.f(e) { + i++ + return fn(e) + } + return true + }) + } else { + f.s.Iterate(func(e T) bool { + if f.f(e) { + return fn(e) + } + return true + }) + } +} + +func (f *filterSeq[T]) Lazy(fn func(func() T) bool) { + if f.limit > 0 { + var i uint64 + f.s.Lazy(func(e func() T) bool { + if i == f.limit { + return false + } + el := e() + if f.f(el) { + i++ + return fn(func() T { return el }) + } + return true + }) + } else { + f.s.Lazy(func(e func() T) bool { + el := e() + if f.f(el) { + return fn(func() T { return el }) + } + return true + }) + } +} + +// Filter takes a Seq[T] 's' and returns a new Seq[T] which contains only +// the elements for which the func `f` returns true. The func `f` should +// be idempotent, as it may be called multiple times on the same element. +func Filter[T any](s Seq[T], f func(T) bool) Seq[T] { + return &filterSeq[T]{ + s: s, + f: f, + } +} + +// ToSlice converts a Seq[T] into a []T. +// +// Note: Running a fold on an unbounded sequence will never terminate. +// One should usually use Split() or Fold() on unbounded sequences first +// to limit the output. +func ToSlice[T any](s Seq[T]) []T { + var sl []T + s.Iterate(func(e T) bool { + sl = append(sl, e) + return true + }) + return sl +} + +// Always takes a function accepting an element T and returns nothing, +// and returns a function that does the same thing but always returns true. +// +// This is useful for calls to Iterate: +// +// seq.Iterate(func(e int) { +// f(e) +// return true +// }) +// +// becomes: +// seq.Iterate(Always(f)) +func Always[T any](f func(e T)) func(e T) bool { + return func(e T) bool { + f(e) + return true + } +} diff --git a/map_test.go b/map_test.go new file mode 100644 index 0000000..6bc09b6 --- /dev/null +++ b/map_test.go @@ -0,0 +1,416 @@ +package ion + +import ( + "fmt" + "io" + "testing" + "time" +) + +func TestSeq(t *testing.T) { + + t.Run("map", func(t *testing.T) { + m := Repeatedly[int](10) + m = Map(m, func(x int) int { return x + 1 }) + if e, ok := m.Elem(10); ok == false || e != 11 { + t.Fatalf("Expected %d == 11", e) + } + }) + + t.Run("repeat-fold", func(t *testing.T) { + m := Repeatedly[int](10) + some, m := m.Split(100) + + ret := Fold(some, func(acc, x int) int { + return acc + x + }) + + if ret != 1000 { + t.Fatalf("Expected %d == 1000", ret) + } + }) + + t.Run("repeat-map-fold", func(t *testing.T) { + m := Repeatedly[int](10) + m = Map(m, func(x int) int { + return x * 10 + }) + some, m := m.Split(100) + + ret := Fold(some, func(acc, x int) int { + return acc + x + }) + + if ret != 10000 { + t.Fatalf("Expected %d == 10000", ret) + } + }) + + t.Run("from", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + + m := From[int](0, 10) + some, m2 := m.Split(10) + if s := Fold(some, sum); s != 450 { + t.Fatalf("Expected %d == 450", s) + } + + some2, _ := m.Split(10) + // splitting m again should give the same some. + if s := Fold(some2, sum); s != 450 { + t.Fatalf("Expected %d == 450", s) + } + + some3, _ := m2.Split(10) + // Using m2 should give the next some. + if s := Fold(some3, sum); s != 1450 { + t.Fatalf("Expected %d == 1450", s) + } + }) + + t.Run("generate", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + + // Unbounded sequence of fibonacci numbers + fibgen := Generate(func(state [2]int) (int, [2]int, bool) { + if state[1] == 0 { + state[1] = 1 + return 0, state, true + } + next := state[0] + state[1] + ret := state[1] + state[0], state[1] = state[1], next + return ret, state, true + }) + // first 10 (0,1,1,2 ..) sum to 88 + some, fg2 := fibgen.Split(10) + if s := Fold(some, sum); s != 88 { + t.Fatalf("Expected %d == 88", s) + } + + // fg2 should give the next 10 (34,55,89...) which sum to + some2, _ := fg2.Split(10) + if s := Fold(some2, sum); s != 10857 { + t.Fatalf("Expected %d == 10857", s) + } + + // the original fibgen should give the original values *and* be able to + // continue generating from the sequence. + // (0,1,1,2,3, ... 55,89,144, ...) Should equal 88 + 10857 == 10945 + some3, _ := fibgen.Split(20) + if s := Fold(some3, sum); s != 10945 { + t.Fatalf("Expected %d == 10945", s) + } + }) + + t.Run("filter", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + isEven := func(i int) bool { return i%2 == 0 } + // Unbounded sequence of natural numbers + naturals := From[int](1, 1) + // Filter the unbounded list, giving only the evens + evens := Filter(naturals, isEven) + // Take 10 + some, _ := evens.Split(10) + if e, ok := some.Elem(0); ok == false || e != 2 { + t.Fatalf("Expected element 0 to be 2, but was %d\n", e) + } + if l := len(ToSlice(some)); l != 10 { + t.Fatalf("Expected len(some) == 10, but it was %d\n", l) + } + if s := Fold(some, sum); s != 110 { + t.Fatalf("Expected %d == 110", s) + } + }) + + t.Run("filter-prime", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + isPrime := func(n int) bool { + if n == 1 { + return false + } + + i := 2 + // check all integers between 2 and sqrt(n) + for i*i <= n { + if n%i == 0 { + return false + } + i += 1 + } + return true + } + + // Unbounded sequence of natural numbers + naturals := From[int](1, 1) + // Filter the unbounded list, giving only the prime numbers + primes := Filter(naturals, isPrime) + // Take 20 + some, _ := primes.Split(20) + if l := len(ToSlice(some)); l != 20 { + t.Fatalf("Expected 20 elements, but only got %d\n", l) + } + if s := Fold(some, sum); s != 639 { + t.Fatalf("Expected %d == 639", s) + } + }) + + t.Run("filter-prime", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + isPrime := func(n int) bool { + if n == 1 { + return false + } + + i := 2 + // check all integers between 2 and sqrt(n) + for i*i <= n { + if n%i == 0 { + return false + } + i += 1 + } + return true + } + result := Fold(Filter(From[int](1, 1), isPrime).Take(1000), sum) + if result != 3682913 { + t.Fatalf("Expected %d == 3682913", result) + } + }) + + t.Run("prime-sieve", func(t *testing.T) { + sum := func(acc, x int) int { return acc + x } + primes := Generate(func(state []int) (int, []int, bool) { + // Sieve of erasthenes (sort of) + // state is the list of primes followed by the current number + if len(state) == 0 { + return 2, []int{2, 3}, true + } + i := state[len(state)-1] + state = state[:len(state)-1] + outter: + for { + for _, p := range state { + if i%p == 0 { + i += 1 + continue outter + } + } + state = append(state, i, i+1) + return i, state, true + } + }) + + // Take 20 + some, _ := primes.Split(20) + if l := len(ToSlice(some)); l != 20 { + t.Fatalf("Expected 20 elements, but got %d\n", l) + } + if s := Fold(some, sum); s != 639 { + t.Fatalf("Expected %d == 639", s) + } + }) + + t.Run("lazy", func(t *testing.T) { + primes := Generate(func(state []int) (int, []int, bool) { + // Sieve of erasthenes (sort of) + // state is the list of primes followed by the current number + if len(state) == 0 { + return 2, []int{2, 3}, true + } + i := state[len(state)-1] + state = state[:len(state)-1] + outter: + for { + for _, p := range state { + if i%p == 0 { + i += 1 + continue outter + } + } + state = append(state, i, i+1) + return i, state, true + } + }) + + some := primes.Take(100001) + //some, _ := primes.Split(100001) + e, ok := some.Elem(0) + if !ok { + t.Fatalf("Expected an element.") + } + t.Logf("Zero: %d\n", e) + //fmt.Printf("100000: %d\n", some.Elem(100000)) + // TODO: Assert laziness somehow. + }) + + t.Run("lazy2", func(t *testing.T) { + naturals := From[int](1, 1) + filtered := Filter(naturals, func(i int) bool { + return i%2 == 0 + }) + + //some, _ := filtered.Split(100000001) + some := filtered.Take(100000001) + e, ok := some.Elem(0) + if !ok { + t.Fatalf("Expected an element.") + } + t.Logf("Zero: %d\n", e) + //fmt.Printf("100000: %d\n", some.Elem(100000000)) + // TODO: Assert laziness somehow. + }) + + // t.Run("play", func(t *testing.T) { + // primes := Generate(func(state []int) (int, []int) { + // // Sieve of erasthenes (sort of) + // // state is the list of primes followed by the current number + // if len(state) == 0 { + // return 2, []int{2, 3} + // } + // i := state[len(state)-1] + // state = state[:len(state)-1] + // outter: + // for { + // for _, p := range state { + // if i%p == 0 { + // i += 1 + // continue outter + // } + // } + // state = append(state, i, i+1) + // return i, state + // } + // }) + + // some, next := primes.Split(10) + // fmt.Printf("First 10: %v\n", ToSlice(some)) + + // primes = Map(primes, func(i int) int { + // fmt.Printf("mapping %d\n", i) + // return i + 1 + // }) + + // fmt.Printf("Split\n") + // some2, _ := primes.Split(10) + // fmt.Printf("Done.\n") + // fmt.Printf("First 10 again: %v\n", ToSlice(some2)) + + // some3, _ := next.Split(10) + // fmt.Printf("Next 10: %v\n", ToSlice(some3)) + // }) +} + +// Regression test. The "need" calculation in Elem functions was +// using unsigned ints and underflowing, creating needs of close to math.MaxUint64 +func TestMapSplitElem(t *testing.T) { + seq := Generate(func(state int) (int, int, bool) { + return state + 1, state + 1, true + }) + seq = Map(seq, func(i int) int { return i + 1 }) + + done := make(chan struct{}) + + go func() { + _, tenth := seq.Split(10) + e, ok := tenth.Elem(0) + if !ok { + t.Fatalf("Expected an element.") + } + fmt.Fprintf(io.Discard, "tenth: %d\n", e) + + e, ok = seq.Elem(0) + if !ok { + t.Fatalf("Expected an element.") + } + fmt.Fprintf(io.Discard, "zeroth: %d\n", e) + close(done) + }() + + // Expect the element to be calculated in < 1 second. + select { + case <-done: + case <-time.After(1 * time.Second): + t.Fatal("Timed out.") + } +} + +func TestMapSplit(t *testing.T) { + seq := Generate(func(state int) (int, int, bool) { + return state, state + 1, true + }) + + m := Map(seq, func(i int) int { + return i + 1 + }) + + m1, m2 := m.Split(1000) + + if e, ok := m.Elem(10); ok == false || e != 11 { + t.Fatalf("Expected m[10] == 11, but was %d\n", e) + } + + if e, ok := m1.Elem(10); ok == false || e != 11 { + t.Fatalf("Expected m1[10] == 11, but was %d\n", e) + } + if e, ok := m2.Elem(10); ok == false || e != 1011 { + t.Fatalf("Expected m2[10] == 1011, but was %d\n", e) + } +} + +func BenchmarkPrimes(b *testing.B) { + b.Run("sieve", func(b *testing.B) { + for i := 0; i < b.N; i++ { + primes := Generate(func(state []int) (int, []int, bool) { + // Sieve of erasthenes (sort of) + // state is the list of primes followed by the current number + if len(state) == 0 { + return 2, []int{2, 3}, true + } + i := state[len(state)-1] + state = state[:len(state)-1] + outter: + for { + for _, p := range state { + if i%p == 0 { + i += 1 + continue outter + } + } + state = append(state, i, i+1) + return i, state, true + } + }) + + // Take 20 + primes.Split(2000) + } + }) + + b.Run("sqrt", func(b *testing.B) { + for i := 0; i < b.N; i++ { + isPrime := func(n int) bool { + if n == 1 { + return false + } + + i := 2 + // check all integers between 2 and sqrt(n) + for i*i <= n { + if n%i == 0 { + return false + } + i += 1 + } + return true + } + + // Unbounded sequence of natural numbers + naturals := From[int](1, 1) + // Filter the unbounded list, giving only the prime numbers + primes := Filter(naturals, isPrime) + // Take 20 + primes.Split(2000) + } + }) +} diff --git a/memo.go b/memo.go new file mode 100644 index 0000000..e5e5f36 --- /dev/null +++ b/memo.go @@ -0,0 +1,121 @@ +package ion + +import ( + "sync" +) + +type memo[T any] struct { + s Seq[T] + mems *Vec[T] + m sync.Mutex +} + +func (m *memo[T]) Elem(i uint64) (T, bool) { + m.m.Lock() + defer m.m.Unlock() + len := m.mems.Len() + if i >= len { + need := i - len + 1 + t, next := m.s.Split(uint64(need)) + m.s = next + news := BuildVec(func(add func(e T)) { + t.Iterate(func(e T) bool { + add(e) + return true + }) + }) + m.mems = m.mems.Join(news) + } + return m.mems.Elem(i) +} + +func (m *memo[T]) Split(n uint64) (Seq[T], Seq[T]) { + m.m.Lock() + defer m.m.Unlock() + memlen := m.mems.Len() + + var sl, sr Seq[T] + if n > memlen { + splits := n - m.mems.Len() + sl, sr = m.s.Split(splits) + } else { + sl = (*Vec[T])(nil) + sr = m.s + } + var ml, mr Seq[T] + if n >= m.mems.Len() { + ml = m.mems + mr = (*Vec[T])(nil) + } else { + ml, mr = m.mems.Split(n) + } + l := &memo[T]{ + s: sl, + mems: ml.(*Vec[T]), + } + r := &memo[T]{ + s: sr, + mems: mr.(*Vec[T]), + } + return l, r +} + +func (m *memo[T]) Take(n uint64) Seq[T] { + m.m.Lock() + defer m.m.Unlock() + splits := int64(n) - int64(m.mems.Len()) + var sl Seq[T] + if splits > 0 { + sl = m.s.Take(uint64(splits)) + } else { + sl = (*Vec[T])(nil) + } + var ml Seq[T] + if n >= m.mems.Len() { + ml = m.mems + } else { + ml = m.mems.Take(n) + } + l := &memo[T]{ + s: sl, + mems: ml.(*Vec[T]), + } + return l +} + +func (m *memo[T]) Iterate(f func(T) bool) { + for i := uint64(0); ; i++ { // TODO: This will only iterate up to math.MaxUint64 elements. + e, ok := m.Elem(i) + if !ok || !f(e) { + return + } + } +} + +func (m *memo[T]) Lazy(f func(func() T) bool) { + quit := false + m.mems.Lazy(func(ef func() T) bool { + if !f(ef) { + quit = true + return false + } + return true + }) + if quit { + return + } + m.s.Lazy(f) // TODO: This is a problem, because we're not memoizing the results. +} + +// Memo takes a Seq[T] `s` and returns a new memoized Seq[T] which is identical, +// except any computations involved in producing elements of `s` are cached, +// and subsequent accesses of those elements return the cached value. +// +// Keep in mind that Memo'd Seq's keep their values in memory, so Memo'ing +// unbounded sequences can lead to unbounded memory usage if you use them +// carelessly. Only Memo sequences when you have a specific reason to do so. +func Memo[T any](s Seq[T]) Seq[T] { + return &memo[T]{ + s: s, + } +} diff --git a/rbtree.go b/rbtree.go new file mode 100644 index 0000000..cad1993 --- /dev/null +++ b/rbtree.go @@ -0,0 +1,745 @@ +package ion + +import ( + "cmp" + "fmt" + "io" +) + +// RBTree is a tree-based map of keys of type T to values of type U. +// +// RBTree is immutable, meaning operations performed on it return +// new trees without modifying the old. Because of the immutable nature +// of the structure, the new tree shares most of its memory with the +// original, meaning operations can be performed efficiently without +// needing to reconstruct an entirely new tree for every operation. +type RBTree[T cmp.Ordered, U any] struct { + c color + k T + v U + l *RBTree[T, U] + r *RBTree[T, U] +} + +// Insert returns a new tree, consisting of the original tree with the +// key/value pair `k`/`v` added to it. +func (r *RBTree[T, U]) Insert(k T, v U) *RBTree[T, U] { + //fmt.Printf("INSERT %d\n", i) + var chain [64]*RBTree[T, U] + return r.tree_insert(k, v, chain[:0]) +} + +// Get looks up the element in the map associated with `k`. +// It also returns a boolean indicating whether the value was found. +func (r *RBTree[T, U]) Get(k T) (U, bool) { + if r == nil { + var r U + return r, false + } + switch { + case r.k == k: + return r.v, true + case r.k < k: + return r.r.Get(k) + case r.k > k: + return r.l.Get(k) + } + panic("Not possible.") +} + +// Dot writes out a graphviz dot formatted directed graph to +// the writer `w`. This can be used with graphviz to visualize +// the tree's internal structure. +func (r *RBTree[T, U]) Dot(w io.Writer) { + fmt.Fprintf(w, "digraph tree {\n") + r.rdot(w, make(map[T]struct{})) + fmt.Fprintf(w, "}\n") +} + +// Size returns the number of elements present in the tree. +func (r *RBTree[T, U]) Size() uint64 { + if r == nil { + return 0 + } + return r.l.Size() + r.r.Size() + 1 +} + +func (r *RBTree[T, U]) rdot(w io.Writer, m map[T]struct{}) { + if r == nil { + return + } + if _, ok := m[r.k]; ok { + return + } + m[r.k] = struct{}{} + + switch r.c { + case red: + fmt.Fprintf(w, "\t%v [color=\"red\"]\n", r.k) + case black: + fmt.Fprintf(w, "\t%v [color=\"black\"]\n", r.k) + } + if r.l != nil { + fmt.Fprintf(w, "\t%v -> %v [color=\"green\"];\n", + r.k, r.l.k) + } + if r.r != nil { + fmt.Fprintf(w, "\t%v -> %v [color=\"yellow\"];\n", + r.k, r.r.k) + } + r.l.rdot(w, m) + r.r.rdot(w, m) +} + +func (r *RBTree[T, U]) right_rotate() *RBTree[T, U] { + if r.l == nil { + // Nothing on the left to + // rotate to the right. + return r + } + + //y := r + //x := r.l + + y := &RBTree[T, U]{ + k: r.k, + v: r.v, + c: r.c, + l: r.l, + r: r.r, + } + x := &RBTree[T, U]{ + k: r.l.k, + v: r.l.v, + c: r.l.c, + l: r.l.l, + r: r.l.r, + } + + a := r.l.l + b := r.l.r + c := r.r + + x.l = a + x.r = y + y.l = b + y.r = c + return x +} + +func (r *RBTree[T, U]) left_rotate() *RBTree[T, U] { + if r.r == nil { + // Nothing on the right to + // rotate to the left. + return r + } + + //x := r + //y := r.r + + x := &RBTree[T, U]{ + k: r.k, + v: r.v, + c: r.c, + l: r.l, + r: r.r, + } + y := &RBTree[T, U]{ + k: r.r.k, + v: r.r.v, + c: r.r.c, + l: r.r.l, + r: r.r.r, + } + + a := r.l + b := r.r.l + c := r.r.r + + y.l = x + y.r = c + x.l = a + x.r = b + return y +} + +type color uint8 + +const ( + red color = iota + black +) + +func root[T cmp.Ordered, U any](n, p, g *RBTree[T, U], chain []*RBTree[T, U]) *RBTree[T, U] { + if len(chain) > 0 { + return chain[0] + } else if g != nil { + return g + } else if p != nil { + return p + } + return n +} + +func npg[T cmp.Ordered, U any](chain []*RBTree[T, U]) (n, p, g *RBTree[T, U], c []*RBTree[T, U]) { + c = chain + if len(c) > 0 { + n = c[len(c)-1] + c = c[:len(c)-1] + } + if len(c) > 0 { + p = c[len(c)-1] + c = c[:len(c)-1] + } + if len(c) > 0 { + g = c[len(c)-1] + c = c[:len(c)-1] + } + return +} + +func next[T cmp.Ordered, U any](c []*RBTree[T, U]) (*RBTree[T, U], []*RBTree[T, U]) { + if len(c) > 0 { + return c[len(c)-1], c[:len(c)-1] + } + return nil, c +} + +func rebalance[T cmp.Ordered, U any](chain []*RBTree[T, U]) *RBTree[T, U] { + n, p, g, chain := npg(chain) + for { + n.c = red + if p == nil { + //fmt.Printf("CASE i3\n") + // Case i3 + // Tree is already balanced. + return n + } + if p.c == black { + //fmt.Printf("CASE i1\n") + // Case i1 + // Tree is already balanced. + return root(n, p, g, chain) + } + // else parent is red + if g == nil { + //fmt.Printf("CASE i4\n") + // Case i4 + p.c = black + return p + } + var u *RBTree[T, U] + if g.l == p { + // Parent is left branch + u = g.r + if u != nil { + u = &RBTree[T, U]{ + k: u.k, + v: u.v, + c: u.c, + l: u.l, + r: u.r, + } + g.r = u + } + } else { + u = g.l + if u != nil { + u = &RBTree[T, U]{ + k: u.k, + v: u.v, + c: u.c, + l: u.l, + r: u.r, + } + g.l = u + } + } + + if u != nil && u.c == red { + //fmt.Printf("CASE i2\n") + // Case i2 + p.c = black + u.c = black + g.c = red + n = g + p, chain = next(chain) + g, chain = next(chain) + continue + } + + var inner bool + // Uncle is black. + // Need to determine i5 vs i6 + if g.l == p { + if p.l == n { + inner = false + } else { + inner = true + } + } else { + if p.r == n { + inner = false + } else { + inner = true + } + } + + if inner { + //fmt.Printf("CASE i5\n") + // Case i5 + // Case i5 does a rotation to turn it into case i6 + if g.l == p { + // parent is on the left. Child on right. Rotate parent left + p = p.left_rotate() + g.l = p + n = p.l + } else { + // parent is on the right. Child on left. Rotate parent right + p = p.right_rotate() + g.r = p + n = p.r + } + } + + //fmt.Printf("CASE i6\n") + // Case i6 + // need the great-grandparent + gg, chain := next(chain) + var left bool + if gg != nil && gg.l == g { + left = true + } + p.c = black + g.c = red + if g.l == p { + // rotate right + g = g.right_rotate() + } else { + // rotate left + g = g.left_rotate() + } + + if gg != nil { + if left { + gg.l = g + } else { + gg.r = g + } + } + // Tree is balanced. Return the root. + return root(p, g, gg, chain) + } +} + +func rechain[T cmp.Ordered, U any](chain []*RBTree[T, U]) []*RBTree[T, U] { + nc := make([]*RBTree[T, U], len(chain)) + prev := &RBTree[T, U]{ + k: chain[0].k, + v: chain[0].v, + c: chain[0].c, + l: chain[0].l, + r: chain[0].r, + } + nc[0] = prev + for i := 1; i < len(chain); i++ { + t := chain[i] + + nt := &RBTree[T, U]{ + k: t.k, + v: t.v, + c: t.c, + l: t.l, + r: t.r, + } + if prev.l == t { + prev.l = nt + } else if prev.r == t { + prev.r = nt + } else { + // fmt.Printf("CHAIN:\n") + // chain[0].Dot(os.Stdout) + // fmt.Printf("EXPECTED %d to be left or right of %d\n", + // t.i, prev.i) + panic("NOT FOUND") + } + nc[i] = nt + prev = nt + } + return nc +} + +func (r *RBTree[T, U]) tree_insert(k T, v U, chain []*RBTree[T, U]) *RBTree[T, U] { + if r == nil { + return &RBTree[T, U]{k: k, v: v} + } + chain = append(chain, r) + switch { + case r.k == k: + r := duplicate(r) + r.v = v + return r + case r.k < k: + if r.r == nil { + chain = rechain(chain) + r = chain[len(chain)-1] + r.r = &RBTree[T, U]{k: k, v: v} + return rebalance(append(chain, r.r)) + } + return r.r.tree_insert(k, v, chain) + + case r.k > k: + if r.l == nil { + chain = rechain(chain) + r = chain[len(chain)-1] + r.l = &RBTree[T, U]{k: k, v: v} + return rebalance(append(chain, r.l)) + } + return r.l.tree_insert(k, v, chain) + } + panic("Not possible.") +} + +// Delete returns a new tree that does not contain the key `k`, and +// a boolean indicating whether or not an element was removed. +func (r *RBTree[T, U]) Delete(k T) (*RBTree[T, U], bool) { + //fmt.Printf("DELETE %d\n", i) + var chain [64]*RBTree[T, U] + return r.tree_delete(k, chain[:0]) +} + +func duplicate[T cmp.Ordered, U any](t *RBTree[T, U]) *RBTree[T, U] { + if t == nil { + return nil + } + return &RBTree[T, U]{ + k: t.k, + v: t.v, + c: t.c, + l: t.l, + r: t.r, + } +} + +func rebalance_del[T cmp.Ordered, U any](chain []*RBTree[T, U]) *RBTree[T, U] { + n, chain := next(chain) + p, chain := next(chain) + + if p == nil { + return nil + } + + var left bool + if p.l == n { + left = true + p.l = nil + } else if p.r == n { + left = false + p.r = nil + } else { + panic("1 Wrong parent") + } + + var s, d, c *RBTree[T, U] + for { + // Everything in the chain has already + // been duplicated, but the siblings and + // nephews have not been yet. We'll duplicate + // them here. + if left { + s = duplicate(p.r) + p.r = s + d = duplicate(s.r) + s.r = d + c = duplicate(s.l) + s.l = c + } else { + s = duplicate(p.l) + p.l = s + d = duplicate(s.l) + s.l = d + c = duplicate(s.r) + s.r = c + } + if s.c == red { + goto d3 + } + if d != nil && d.c == red { + goto d6 + } + if c != nil && c.c == red { + goto d5 + } + if p.c == red { + goto d4 + } + + // case D2 p, c, s, d all black + //fmt.Printf("Case d2\n") + s.c = red + n = p + // Not in the original + p, chain = next(chain) + if p == nil { + //fmt.Printf("Case d1\n") + return n + } + if p.l == n { + left = true + } else if p.r == n { + left = false + } else { + panic("3 AAAAHHHH") + } + } + +d3: + //fmt.Printf("Case d3\n") + { + var np, oldp *RBTree[T, U] + if left { + np = p.left_rotate() + oldp = p + p = np.l + + p.c = red + np.c = black //s.c = black + s = c + // C has been duplicated, but c's kids haven't. + if s != nil { + d = duplicate(s.r) + s.r = d + c = duplicate(s.l) + s.l = c + } else { + d = nil + c = nil + } + } else { + np = p.right_rotate() + oldp = p + p = np.r + p.c = red + np.c = black //s.c = black + s = c + if s != nil { + d = duplicate(s.l) + s.l = d + c = duplicate(s.r) + s.r = c + } else { + d = nil + c = nil + } + } + if len(chain) > 0 { + g := chain[len(chain)-1] + if g.l == oldp { + g.l = np + } else if g.r == oldp { + g.r = np + } else { + panic("20 Fail") + } + } + // p used to be the root. Now np is the root. + // Need to push np into the chain. + chain = append(chain, np) + + if d != nil && d.c == red { + goto d6 + } + if c != nil && c.c == red { + goto d5 + } + } + +d4: + //fmt.Printf("Case d4\n") + if s != nil { + s.c = red + } + p.c = black + if len(chain) > 0 { + return chain[0] + } + return p + +d5: + //fmt.Printf("Case d5\n") + if left { + ns := s.right_rotate() + p.r = ns + s = ns.r + } else { + ns := s.left_rotate() + p.l = ns + s = ns.l + } + s.c = red + c.c = black + d = s + s = c +d6: + //fmt.Printf("Case d6\n") + var np, oldp *RBTree[T, U] + if left { + np = p.left_rotate() + oldp = p + p = np.l + s = np + } else { + np = p.right_rotate() + oldp = p + p = np.r + s = np + } + if len(chain) > 0 { + g := chain[len(chain)-1] + if g.l == oldp { + //fmt.Printf("2 %d left -> %d\n", g.i, np.i) + g.l = np + } else if g.r == oldp { + g.r = np + } else { + fmt.Printf("expected %v to gave child %v but it does not.\n", g.k, p.k) + panic("2 Fail") + } + } + s.c = p.c + p.c = black + d.c = black + if len(chain) > 0 { + return chain[0] + } + return np +} + +func replace[T cmp.Ordered, U any](t *RBTree[T, U], i, j T) { + switch { + case t.k == i: + t.k = j + case t.k < i: + replace(t.r, i, j) + case t.k > i: + replace(t.l, i, j) + } + return +} + +func (r *RBTree[T, U]) tree_delete(k T, chain []*RBTree[T, U]) (*RBTree[T, U], bool) { + if r == nil { + return nil, false + } + chain = append(chain, r) + switch { + case r.k == k: + if r.l != nil && r.r != nil { + // can swap our value with our in-order predecessor + predec, newTree := r.l.removeLargest(chain) + // It is safe to modify newTree because the node containing r.i + // will be new within newTree. + // This can be optimized in the future so we don't have to + // re-traverse the tree to find i. + replace(newTree, r.k, predec.k) + return newTree, true + } else if r.l != nil { + // Only left child + // replace this node with it's child and color it black. + chain = rechain(chain) + r = chain[len(chain)-1] + r.l = &RBTree[T, U]{ + k: r.l.k, + v: r.l.v, + c: r.l.c, + l: r.l.l, + r: r.l.r, + } + r.l.c = black + if len(chain) > 1 { + p := chain[len(chain)-2] + if p.l == r { + p.l = r.l + } else if p.r == r { + p.r = r.l + } else { + panic("foo") + } + return chain[0], true + } + return r.l, true + } else if r.r != nil { + // Only left child + // replace this node with its child and color it black. + chain = rechain(chain) + r = chain[len(chain)-1] + r.l = &RBTree[T, U]{ + k: r.r.k, + v: r.r.v, + c: r.r.c, + l: r.r.l, + r: r.r.r, + } + r.r.c = black + if len(chain) > 1 { + p := chain[len(chain)-2] + if p.l == r { + p.l = r.r + } else if p.r == r { + p.r = r.r + } else { + panic("foo") + } + return chain[0], true + } + return r.r, true + } else { + // No children + if len(chain) == 1 { + // No children and we are the root. + return nil, true + } + chain = rechain(chain) + r = chain[len(chain)-1] + p := chain[len(chain)-2] + if r.c == red { + if p.l == r { + p.l = nil + } else if p.r == r { + p.r = nil + } else { + panic("foo2") + } + // No children and we are a red node. + return chain[0], true + } + // No children and we are a black node. This will create an imbalance + // and we need to fix the tree. + //return rebalance_del(chain), true + rb := rebalance_del(chain) + return rb, true + } + case r.k > k: + if nl, ok := r.l.tree_delete(k, chain); ok { + return nl, true + } + return chain[0], false + case r.k < k: + if nr, ok := r.r.tree_delete(k, chain); ok { + return nr, true + } + return chain[0], false + } + panic("not possible.") +} + +func (t *RBTree[T, U]) removeLargest(chain []*RBTree[T, U]) (largest, tree *RBTree[T, U]) { + if t.r != nil { + return t.r.removeLargest(append(chain, t)) + } + + // We found the rightmost. We will delete() the current node and return the tree. + d, _ := t.tree_delete(t.k, chain) + return t, d + +} diff --git a/rbtree_test.go b/rbtree_test.go new file mode 100644 index 0000000..c57f179 --- /dev/null +++ b/rbtree_test.go @@ -0,0 +1,350 @@ +package ion + +import ( + "fmt" + "math/rand" + "os" + "testing" +) + +func FuzzRBConsistency(f *testing.F) { + f.Add(make([]byte, 9000)) + // The format of the byte array is a series of elements of 9 bytes: + // [0][1][2][3][4][5][6][7][8] + // Byte 0 % 2 determines if the operation is an insertion or a deletion + // Bytes 1-8 are the 64-bit integer + // Dangling bytes not totalling 9 bytes are excluded. + f.Fuzz(func(t *testing.T, val []byte) { + var tr *RBTree[uint64, uint64] + for len(val) >= 9 { + insert := val[0]%2 == 0 + v := uint64(val[1]) | + (uint64(val[2]) << 8) | + (uint64(val[3]) << 16) | + (uint64(val[4]) << 24) | + (uint64(val[5]) << 32) | + (uint64(val[6]) << 40) | + (uint64(val[7]) << 48) | + (uint64(val[8]) << 56) + val = val[9:] + + if insert { + tr = tr.Insert(v, v) + } else { + tr, _ = tr.Delete(v) + } + if n := validateRBTree(tr); n != nil { + tr.Dot(os.Stdout) + t.Fatalf("Failed to validate tree: %v\n", n) + } + // if ftr := checkHeight(t, tr); ftr != nil { + // t.Fatalf("Bad height for node %#v\n", ftr) + // } + // if ftr := checkBalance(t, tr); ftr != nil { + // // f, _ := os.Create("after.dot") + // // tr.Dot(f) + // // f.Close() + // if insert { + // t.Logf("After insert of %d\n", v) + // } else { + // t.Logf("After delete of %d\n", v) + // } + // t.Fatalf("Bad balance for node %v\n", ftr) + // } + } + + }) +} + +func FuzzRBInsDel(f *testing.F) { + f.Add(make([]byte, 9000)) + // The format of the byte array is a series of elements of 9 bytes: + // [0][1][2][3][4][5][6][7][8] + // Byte 0 % 2 determines if the operation is an insertion or a deletion + // Bytes 1-8 are the 64-bit integer + // Dangling bytes not totalling 9 bytes are excluded. + f.Fuzz(func(t *testing.T, val []byte) { + var tr *RBTree[uint64, uint64] + ks := make(map[uint64]struct{}) + var dels []uint64 + sz := 0 + szd := 0 + for len(val) >= 9 { + del := val[0]%2 == 0 + v := uint64(val[1]) | + (uint64(val[2]) << 8) | + (uint64(val[3]) << 16) | + (uint64(val[4]) << 24) | + (uint64(val[5]) << 32) | + (uint64(val[6]) << 40) | + (uint64(val[7]) << 48) | + (uint64(val[8]) << 56) + val = val[9:] + s := tr.Size() + if _, ok := ks[v]; !ok { + ntr := tr.Insert(v, v) + ks[v] = struct{}{} + sz++ + tr = ntr + if tr.Size() != s+1 { + tr.Dot(os.Stdout) + t.Fatalf("Wrong size after inserting %d. Expected %d, but got %d\n", + v, s+1, tr.Size()) + } + if del { + // Store some of the values to delete later. + dels = append(dels, v) + szd++ + } + } + } + //fmt.Printf("Pre-deletes\n") + //tr.Dot(os.Stdout) + + otr := tr + for _, k := range dels { + s := tr.Size() + ntr, ok := tr.Delete(k) + if !ok { + fmt.Printf("Before delete %d\n", k) + tr.Dot(os.Stdout) + fmt.Printf("After delete %d\n", k) + ntr.Dot(os.Stdout) + t.Fatalf("Expected to delete %d, but failed.", k) + } + tr = ntr + //fmt.Printf("After delete %d\n", k) + //tr.Dot(os.Stdout) + if tr.Size() != s-1 { + tr.Dot(os.Stdout) + t.Fatalf("Wrong size after deleting %d. Expected %d, but got %d\n", + k, s-1, tr.Size()) + } + } + + if tr.Size() != uint64(sz-len(dels)) { + t.Fatalf("Expected tree size to be %d, but was %d\n", + sz-len(dels), tr.Size()) + } + if otr.Size() != uint64(sz) { + t.Fatalf("Original tree lost some elements during delete.\n") + } + }) +} + +// func TestRBC1(t *testing.T) { + +// var tr *RBTree +// tr1, _ := tr.Insert(1) +// tr2, _ := tr1.Insert(2) +// tr3, _ := tr2.Insert(3) +// tr4, _ := tr3.Insert(4) +// tr5, _ := tr4.Insert(5) + +// tr6, _ := tr5.Delete(1) +// tr7, _ := tr6.Delete(2) +// tr8, _ := tr7.Delete(3) +// tr9, _ := tr8.Delete(4) +// tr10, _ := tr9.Delete(5) + +// tr1.Dot(os.Stdout) +// tr2.Dot(os.Stdout) +// tr3.Dot(os.Stdout) +// tr4.Dot(os.Stdout) +// tr5.Dot(os.Stdout) + +// tr6.Dot(os.Stdout) +// tr7.Dot(os.Stdout) +// tr8.Dot(os.Stdout) +// tr9.Dot(os.Stdout) +// tr10.Dot(os.Stdout) +// } + +// func TestRBC2(t *testing.T) { +// var tr *RBTree +// tr, _ = tr.Insert(3544385890265608240) +// tr, _ = tr.Insert(3616443484303536176) +// tr, _ = tr.Insert(3472328296227680304) +// fmt.Printf("PRE:\n") +// tr.Dot(os.Stdout) +// tr, _ = tr.Delete(3544385890265608240) +// //REMOVE LARGEST! +// //DELETE 3616443484303536176 +// //DELETE 3472328296227680304 + +// tr.Dot(os.Stdout) + +// if n := validateRBTree(tr); n != nil { +// tr.Dot(os.Stdout) +// t.Fatalf("Failed to validate tree: %v\n", n) +// } +// } + +func TestRBInsert(t *testing.T) { + var tr *RBTree[uint64, uint64] + for i := uint64(0); i <= 5000; i++ { + ntr := tr.Insert(i, i) + if tr.Size() != i { + t.Fatalf("Inserting %d: tree was modified.\n", i) + } + tr = ntr + } + + for i := uint64(0); i <= 5000; i++ { + j, ok := tr.Get(i) + if !ok { + t.Errorf("Expected to find %d in the tree, but did not.", i) + } + if j != i { + t.Error("Expected j == i") + } + } +} + +func TestRBTree(t *testing.T) { + var tr *RBTree[uint64, uint64] + for i := uint64(1); i <= 50; i++ { + tr = tr.Insert(i, i) + } + + if n := validateRBTree(tr); n != nil { + tr.Dot(os.Stdout) + t.Fatalf("Failed to validate tree: %v\n", n) + } + + for i := uint64(1); i <= 50; i++ { + j, ok := tr.Get(i) + if !ok { + t.Errorf("Expected to find %d in the tree, but did not.", i) + } + if j != i { + t.Error("Expected j == i") + } + } +} + +// func TestRBRotate(t *testing.T) { +// a := &RBTree{i: 1} +// b := &RBTree{i: 2} +// c := &RBTree{i: 3} +// x := &RBTree{i: 9, l: a, r: b} +// y := &RBTree{i: 10, l: x, r: c} + +// newY := y.right_rotate() +// if newY != x { +// t.Errorf("Expected x to be new root.\n") +// } +// if x.l != a { +// t.Errorf("Expected x.l == a\n") +// } +// if x.r != y { +// t.Errorf("Expected x.r == y\n") +// } +// if y.l != b { +// t.Errorf("Expected y.l == b\n") +// } +// if y.r != c { +// t.Errorf("Expected y.r == c\n") +// } + +// newX := newY.left_rotate() +// if newX != y { +// t.Errorf("Expected x to be new root.\n") +// } +// if x.l != a { +// t.Errorf("Expected x.l == a\n") +// } +// if x.r != b { +// t.Errorf("Expected x.r == b\n") +// } +// if y.l != x { +// t.Errorf("Expected y.l == x\n") +// } +// if y.r != c { +// t.Errorf("Expected y.r == c\n") +// } +// } + +func BenchmarkRBTree(b *testing.B) { + var t *RBTree[uint64, uint64] + + for i := 0; i < b.N; i++ { + r := rand.Uint64() + t = t.Insert(r, r) + } +} + +func TestRBTreeDelete(t *testing.T) { + var tr *RBTree[uint64, uint64] + + for i := uint64(1); i < 20; i++ { + tr = tr.Insert(i, i) + } + if n := validateRBTree(tr); n != nil { + tr.Dot(os.Stdout) + t.Fatalf("Failed to validate tree: %v\n", n) + } + //tr.Dot(os.Stdout) + + tr, _ = tr.Delete(1) + + if n := validateRBTree(tr); n != nil { + tr.Dot(os.Stdout) + t.Fatalf("Failed to validate tree: %v\n", n) + } + + //tr.Dot(os.Stdout) + +} + +func blackDepth(t *RBTree[uint64, uint64], count int) int { + if t.c == black { + count++ + } + if t.l != nil { + return blackDepth(t.l, count) + } + if t.r != nil { + return blackDepth(t.r, count) + } + return count +} + +func validateRBTree(t *RBTree[uint64, uint64]) *RBTree[uint64, uint64] { + if t == nil { + return nil + } + depth := blackDepth(t, 0) + //fmt.Printf("EXPECTING DEPTH %d\n", depth) + return validateRBTreer(t, 0, depth) +} + +func validateRBTreer(t *RBTree[uint64, uint64], count, depth int) *RBTree[uint64, uint64] { + if t.c == black { + count++ + //fmt.Printf("%d count -> %d\n", t.i, count) + } else { + if t.l != nil && t.r == nil || + t.l == nil && t.r != nil { + //fmt.Printf("Found red node %v with 1 child\n", t) + return t + } + } + if t.l != nil { + if n := validateRBTreer(t.l, count, depth); n != nil { + return n + } + } + if t.r != nil { + if n := validateRBTreer(t.r, count, depth); n != nil { + return n + } + } + if t.r == nil && t.l == nil { + if count != depth { + //fmt.Printf("Found black node %v at wrong depth. Depth was %d, expected %d\n", t, count, depth) + return t + } + } + return nil +} diff --git a/repeatedly_test.go b/repeatedly_test.go new file mode 100644 index 0000000..a4fdddf --- /dev/null +++ b/repeatedly_test.go @@ -0,0 +1,165 @@ +package ion + +import ( + "testing" +) + +func TestRepeatedlyInf(t *testing.T) { + // This one we can't use testInfSeq. + s := Repeatedly(1) + t.Run(t.Name()+"/elem", func(t *testing.T) { + for j := 0; j < 2; j++ { + i, ok := s.Elem(100) + if !ok { + t.Fatalf("Expected s[100] to return a value, but got nothing.\n") + } + if i != 1 { + t.Fatalf("Expected s[100] == 1, but got %d\n", i) + } + } + }) + t.Run("/split-end", func(t *testing.T) { + l, _ := s.Split(100) + l, r := l.Split(100) + + ret := Fold(l, func(acc, i int) int { + return acc + i + }) + if ret != 100 { + t.Fatalf("Expected ret == 100, but got %d\n", ret) + } + ret = Fold(r, func(acc, i int) int { + return acc + i + }) + if ret != 0 { + t.Fatalf("Expected ret == 0, but got %d\n", ret) + } + }) + t.Run(t.Name()+"/split", func(t *testing.T) { + for j := 0; j < 2; j++ { + l, r := s.Split(10000) + + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + return acc + i + }) + if res != 10000 { + t.Fatalf("Expected res == 10000, but was %d", res) + } + + var j int + l.Iterate(func(i int) bool { + j += i + return true + }) + if j != 10000 { + t.Fatalf("Expected res == 10000, but was %d", j) + } + + // Make sure l only contains what we expect. + e, ok := l.Elem(9999) + if !ok { + t.Fatalf("Expected l[9999] to return a value, but got nothing.\n") + } + if e != 1 { + t.Fatalf("Expected l[9999] == 1, but got %d\n", e) + } + + // Make sure r contains what we expect. + e, ok = r.Elem(0) + if !ok { + t.Fatalf("Expected r[0] to return a value, but got nothing.\n") + } + if e != 1 { + t.Fatalf("Expected r[0] == 1, but got %d\n", e) + } + + // Make sure we can split l again + ll, lr := l.Split(10) + res = Fold(ll, func(acc, i int) int { + return acc + i + }) + if res != 10 { + t.Fatalf("Expected res == 10, but was %d", res) + } + + res = Fold(lr, func(acc, i int) int { + return acc + i + }) + if res != 9990 { + t.Fatalf("Expected res == 9990, but was %d", res) + } + + // Make sure we can split r again + rl, rr := r.Split(10) + res = Fold(rl, func(acc, i int) int { + return acc + i + }) + if res != 10 { + t.Fatalf("Expected res == 10, but was %d", res) + } + + e, ok = rr.Elem(0) + if !ok { + t.Fatalf("Expected rr[0] to return a value, but got nothing.\n") + } + if e != 1 { + t.Fatalf("Expected rr[0] == 1, but got %d\n", e) + } + } + }) + + t.Run(t.Name()+"/take", func(t *testing.T) { + for j := 0; j < 2; j++ { + l := s.Take(10000) + + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + return acc + i + }) + if res != 10000 { + t.Fatalf("Expected res == 10000, but was %d", res) + } + } + }) + + t.Run(t.Name()+"/iterate", func(t *testing.T) { + for j := 0; j < 2; j++ { + var i, res int + + s.Iterate(func(e int) bool { + res += e + i++ + if i == 10000 { + return false + } + return true + }) + + // Make sure l contains what we expect + if res != 10000 { + t.Fatalf("Expected res == 10000, but was %d", res) + } + } + }) + + t.Run(t.Name()+"/lazy", func(t *testing.T) { + for j := 0; j < 2; j++ { + var i, res int + + s.Lazy(func(e func() int) bool { + res += e() + i++ + if i == 10000 { + return false + } + return true + }) + + // Make sure l contains what we expect + if res != 10000 { + t.Fatalf("Expected res == 10000, but was %d", res) + } + } + }) +} diff --git a/result/result.go b/result/result.go new file mode 100644 index 0000000..f0eb63b --- /dev/null +++ b/result/result.go @@ -0,0 +1,119 @@ +// package result is an experiment in monadic types. +// The main type is the Res[T], representing the result of some computation. +// It is useful to use Res in ion.Seq[Res[T]] sequences, since it can +// capture and propagate errors during I/O or other non-pure functions. +package result + +import "github.com/knusbaum/ion" + +// We can't have a Monad type since U must be +// resolved at instantiation time, meaning Map() cannot +// be polymorphic, unless we use interface{}. +// In other words, a type `someStruct[T any]` cannot have methods (like map) +// which are themselves polymorphic beyond the type parameters given +// upon someStruct's instantiation. So: +// func (t *someStruct[T]) Hello(e T) {} +// is fine, but +// func(t *someStruct[T])[U any]map(func(e T) U) T[U] +// is not legal. +// There's also no way to specify that the result of calling Map +// on type T[U], func(U) V is T[V]. +//type Monad[T any] interface { +// ID() T +// Map(func (e T) U) U +//} +// +// type Monad[T any] interface { +// Map(func(e T) U) any +// } +// +// func Map[T, U any, M [T]Monad](e M, f func(e T) U) M[U] { +// return e.Map(f) +// } + +// Res contains the result of a computation. This can be a value +// of type T, or an error. +// Note: Experimental +type Res[T any] struct { + e T + err error +} + +// Get returns the value of type T, and any error held by the Res[T]. +// If ther error is not nil, the T is the zero value. +func (r *Res[T]) Get() (T, error) { + return r.e, r.err +} + +// OK returns a new Res[T] containing `e`. +func Ok[T any](e T) Res[T] { + return Res[T]{ + e: e, + } +} + +// Err returns a new Res[T] containing the error `e`. +func Err[T any](e error) Res[T] { + return Res[T]{ + err: e, + } +} + +// FMap f func(T) -> func(Res[T]) Res[U] +// FMap takes a function `f` that takes a value of type T and returns +// a value of type U. FMap returns a func that takes a value of type Res[T] +// and applies `f` to the value of type T contained in the result, wrapping +// the value of type U into a Result. +// +// If the Res[T] is an error result, the function `f` is not called on it, and +// the Res[T] is converted to Res[U], its error. +func FMap[T, U any](f func(e T) U) func(Res[T]) Res[U] { + return func(r Res[T]) Res[U] { + if r.err != nil { + return Err[U](r.err) + } + return Ok(f(r.e)) + } +} + +// Apply f func(T) -> func(Res[T]) +// Apply takes a function `f` that takes a value of type T and Apply returns a +// func that takes a value of type Res[T] and applies `f` to the value of type T +// contained in the result. If the Res[T] is an error result, the function `f` +// is not called on it. +func Apply[T any](f func(e T)) func(Res[T]) { + return func(r Res[T]) { + if r.err != nil { + return + } + f(r.e) + } +} + +// Handle f func(error) -> func(Res[T]) Res[T] +// Handle takes a function designed to handle errors and returns +// a function that will apply that handler function to a Res[T], +// if the Res[T] is an error result. +func Handle[T any](f func(e error)) func(Res[T]) Res[T] { + return func(r Res[T]) Res[T] { + if r.err != nil { + f(r.err) + } + return r + } +} + +// Map s Seq[Res[T]] -> f func(T) U -> Seq[Res[U]] +// Map is analogous to ion.Map, only it maps a function from T to U over +// a Seq[Result[T]], returning Seq[Result[U]]. +// +// The resulting sequence contains f applied to the elements of type T +// of the Res[T]s where those Res[T]'s are not errors. Res[T] elements that +// are errors are converted from Res[T] to Res[U] retaining their errors. +// +// Map(s, f) is equivalent to +// +// ion.Map(s, FMap(f)) +func Map[T, U any](s ion.Seq[Res[T]], f func(T) U) ion.Seq[Res[U]] { + return ion.Map(s, FMap(f)) +} diff --git a/seq_test.go b/seq_test.go new file mode 100644 index 0000000..9acef21 --- /dev/null +++ b/seq_test.go @@ -0,0 +1,574 @@ +package ion + +import ( + "math" + "testing" +) + +// testInfSeq expects s to be an unbounded Seq[int] starting at 0 and incrementing by 1 +func testInfSeq(t *testing.T, s Seq[int]) { + t.Run("elem", func(t *testing.T) { + for j := 0; j < 2; j++ { + i, ok := s.Elem(100) + if !ok { + t.Fatalf("Expected s[100] to return a value, but got nothing.\n") + } + if i != 100 { + t.Fatalf("Expected s[100] == 100, but got %d\n", i) + } + } + }) + t.Run("split-end", func(t *testing.T) { + l, _ := s.Split(100) + l, r := l.Split(100) + + ret := Fold(l, func(acc, i int) int { + return acc + i + }) + if ret != 4950 { + t.Fatalf("Expected ret == 4950, but got %d\n", ret) + } + + ret = Fold(r, func(acc, i int) int { + return acc + i + }) + if ret != 0 { + t.Fatalf("Expected ret == 0, but got %d\n", ret) + } + }) + t.Run("split", func(t *testing.T) { + for j := 0; j < 2; j++ { + l, r := s.Split(10000) + + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + return acc + i + }) + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + + var j int + l.Iterate(func(i int) bool { + j += i + return true + }) + if j != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", j) + } + + // Make sure l only contains what we expect. + e, ok := l.Elem(9999) + if !ok { + t.Fatalf("Expected l[9999] to return a value, but got nothing.\n") + } + if e != 9999 { + t.Fatalf("Expected l[9999] == 9999, but got %d\n", e) + } + + // Make sure r contains what we expect. + e, ok = r.Elem(0) + if !ok { + t.Fatalf("Expected r[0] to return a value, but got nothing.\n") + } + if e != 10000 { + t.Fatalf("Expected r[0] == 10000, but got %d\n", e) + } + + // Make sure we can split l again + ll, lr := l.Split(10) + res = Fold(ll, func(acc, i int) int { + return acc + i + }) + if res != 45 { + t.Fatalf("Expected res == 45, but was %d", res) + } + + res = Fold(lr, func(acc, i int) int { + return acc + i + }) + if res != 49994955 { + t.Fatalf("Expected res == 49994955, but was %d", res) + } + + // Make sure we can split r again + rl, rr := r.Split(10) + res = Fold(rl, func(acc, i int) int { + return acc + i + }) + if res != 100045 { + t.Fatalf("Expected res == 100045, but was %d", res) + } + + e, ok = rr.Elem(0) + if !ok { + t.Fatalf("Expected rr[0] to return a value, but got nothing.\n") + } + if e != 10010 { + t.Fatalf("Expected rr[0] == 10010, but got %d\n", e) + } + } + }) + + t.Run("take", func(t *testing.T) { + for j := 0; j < 2; j++ { + l := s.Take(10000) + + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + return acc + i + }) + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) + + t.Run("iterate", func(t *testing.T) { + for j := 0; j < 2; j++ { + var i, res int + s.Iterate(func(e int) bool { + res += e + i++ + if i >= 10000 { + return false + } + return true + }) + + // Make sure l contains what we expect + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) + + t.Run("lazy", func(t *testing.T) { + for j := 0; j < 2; j++ { + var i, res int + + s.Lazy(func(e func() int) bool { + res += e() + i++ + if i == 10000 { + return false + } + return true + }) + + // Make sure l contains what we expect + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) +} + +// testFinSeq expects s to be a Seq[int] of length 10,000 starting at 0 and incrementing by 1 +func testFinSeq(t *testing.T, s Seq[int]) { + t.Run("elem", func(t *testing.T) { + for j := 0; j < 2; j++ { + i, ok := s.Elem(9_999) + if !ok { + t.Fatalf("Expected s[9_999] to return a value, but got nothing.\n") + } + if i != 9_999 { + t.Fatalf("Expected s[9_999] == 9_999, but got %d\n", i) + } + + i, ok = s.Elem(10_000) + if ok { + t.Fatalf("Expected s[10_000] to return no value, but got %d.\n", i) + } + if i != 0 { + t.Fatalf("Expected s[10_000] == 0, but got %d\n", i) + } + } + }) + t.Run("split-end", func(t *testing.T) { + l, _ := s.Split(10000) + l, r := l.Split(10000) + + ret := Fold(l, func(acc, i int) int { + return acc + i + }) + if ret != 49995000 { + t.Fatalf("Expected ret == 4950, but got %d\n", ret) + } + ret = Fold(r, func(acc, i int) int { + return acc + i + }) + if ret != 0 { + t.Fatalf("Expected ret == 0, but got %d\n", ret) + } + }) + t.Run("split", func(t *testing.T) { + for j := 0; j < 2; j++ { + l, r := s.Split(1000) + + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + return acc + i + }) + if res != 499500 { + t.Fatalf("Expected res == 499500, but was %d", res) + } + + var j int + l.Iterate(func(i int) bool { + j += i + return true + }) + if j != 499500 { + t.Fatalf("Expected res == 499500, but was %d", j) + } + + // Make sure l only contains what we expect. + e, ok := l.Elem(9999) + if ok { + t.Fatalf("Expected l[9999] to return no value, but got %d.\n", e) + } + if e != 0 { + t.Fatalf("Expected l[9999] == 0, but got %d\n", e) + } + + // Make sure r contains what we expect. + e, ok = r.Elem(0) + if !ok { + t.Fatalf("Expected r[0] to return a value, but got nothing.\n") + } + if e != 1000 { + t.Fatalf("Expected r[0] == 1000, but got %d\n", e) + } + + // Make sure we can split l again + ll, lr := l.Split(10) + res = Fold(ll, func(acc, i int) int { + return acc + i + }) + if res != 45 { + t.Fatalf("Expected res == 45, but was %d", res) + } + + res = Fold(lr, func(acc, i int) int { + return acc + i + }) + if res != 499455 { + t.Fatalf("Expected res == 499455, but was %d", res) + } + + // Make sure we can split r again + rl, rr := r.Split(10) + res = Fold(rl, func(acc, i int) int { + return acc + i + }) + if res != 10045 { + t.Fatalf("Expected res == 10045, but was %d", res) + } + + e, ok = rr.Elem(0) + if !ok { + t.Fatalf("Expected rr[0] to return a value, but got nothing.\n") + } + if e != 1010 { + t.Fatalf("Expected rr[0] == 1010, but got %d\n", e) + } + + sum := func(s Seq[int]) int { + return Fold(s, func(acc, i int) int { + return acc + i + }) + } + + // Make sure s split on idx > len(s) does not panic. + sbig, snothing := s.Split(200_000) + if res := sum(sbig); res != 49995000 { + t.Fatalf("Expected sum(sbig) == 49995000, but was %d", res) + } + if res := sum(snothing); res != 0 { + t.Fatalf("Expected sum(snothing) == 0, but was %d", res) + } + + // Make sure l split on idx > len(l) does not panic. + lbig, lnothing := l.Split(2000) + if res := sum(lbig); res != 499500 { + t.Fatalf("Expected sum(lbig) == 499500, but was %d", res) + } + if res := sum(lnothing); res != 0 { + t.Fatalf("Expected sum(lnothing) == 0, but was %d", res) + } + + // Make sure r split on idx > len(r) does not panic. + re, ok := r.Elem(0) + if !ok { + t.Fatalf("Expected r[0] to return a value, but got nothing.\n") + } + if re != 1000 { + t.Fatalf("Expected r == 1000, but was %d\n", re) + } + rbig, rnothing := r.Split(10000) + if res := sum(rbig); res != 49495500 { + t.Fatalf("Expected sum(rbig) == 49495500, but was %d", res) + } + if res := sum(rnothing); res != 0 { + t.Fatalf("Expected sum(rnothing) == 0, but was %d", res) + } + } + }) + + t.Run("take", func(t *testing.T) { + for j := 0; j < 2; j++ { + l := s.Take(200000) + + var s int + // Make sure l contains what we expect + res := Fold(l, func(acc, i int) int { + s += i + return acc + i + }) + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) + + t.Run("iterate", func(t *testing.T) { + for j := 0; j < 2; j++ { + var res int + s.Iterate(func(e int) bool { + res += e + return true + }) + + // Make sure l contains what we expect + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) + + t.Run("lazy", func(t *testing.T) { + for j := 0; j < 2; j++ { + var i, res int + + s.Lazy(func(e func() int) bool { + res += e() + i++ + //fmt.Printf("I: %d\n", i) + if i > 10000 { + t.Fatalf("OVER") + } + return true + }) + + // Make sure l contains what we expect + if res != 49995000 { + t.Fatalf("Expected res == 49995000, but was %d", res) + } + } + }) +} + +func TestFilter(t *testing.T) { + g := Generate(func(state [2]int) (int, [2]int, bool) { + // state[0] is next. state[1] starts as int max. + // state[0] and state[1] alternate, generating a sequence that looks like: + // 0, max, 1, max, 2, max, 3, max + // This lets the Filter remove the max int values, leaving the expected sequence + // 0, 1, 2, 3, ... + + if state[0] == 0 { + // initial + state[1] = math.MaxInt + } + + ret := state[0] + if state[0] != math.MaxInt { + state[0]++ + } + state[0], state[1] = state[1], state[0] + return ret, state, true + + }) + t.Run("inf", func(t *testing.T) { + testInfSeq(t, Filter(g, func(i int) bool { + return i != math.MaxInt + })) + }) + t.Run("fin1", func(t *testing.T) { + testFinSeq(t, Filter(g, func(i int) bool { + return i != math.MaxInt + }).Take(10000)) + }) + t.Run("fin2", func(t *testing.T) { + l, _ := Filter(g, func(i int) bool { + return i != math.MaxInt + }).Split(10000) + testFinSeq(t, l) + }) +} + +func TestFrom(t *testing.T) { + t.Run("inf", func(t *testing.T) { + testInfSeq(t, From[int](0, 1)) + }) + t.Run("fin1", func(t *testing.T) { + testFinSeq(t, From[int](0, 1).Take(10000)) + }) + t.Run("fin2", func(t *testing.T) { + l, _ := From[int](0, 1).Split(10000) + testFinSeq(t, l) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("inf", func(t *testing.T) { + testInfSeq(t, Generate(func(state int) (int, int, bool) { + return state, state + 1, true + })) + }) + t.Run("fin1", func(t *testing.T) { + s := Generate(func(state int) (int, int, bool) { + if state >= 10000 { + return 0, state, false + } + return state, state + 1, true + }) + testFinSeq(t, s) + }) + t.Run("fin2", func(t *testing.T) { + testFinSeq(t, Generate(func(state int) (int, int, bool) { + return state, state + 1, true + }).Take(10000)) + }) + t.Run("fin3", func(t *testing.T) { + l, _ := Generate(func(state int) (int, int, bool) { + return state, state + 1, true + }).Split(10000) + testFinSeq(t, l) + }) +} + +func TestGenerateInit(t *testing.T) { + t.Run("inf", func(t *testing.T) { + testInfSeq(t, GenerateInit(100, func(state int) (int, int, bool) { + return state - 100, state + 1, true + })) + }) + t.Run("fin1", func(t *testing.T) { + s := GenerateInit(100, func(state int) (int, int, bool) { + if state-100 >= 10000 { + return 0, state, false + } + return state - 100, state + 1, true + }) + testFinSeq(t, s) + }) + t.Run("fin2", func(t *testing.T) { + testFinSeq(t, GenerateInit(100, func(state int) (int, int, bool) { + return state - 100, state + 1, true + }).Take(10000)) + }) + t.Run("fin3", func(t *testing.T) { + l, _ := GenerateInit(100, func(state int) (int, int, bool) { + return state - 100, state + 1, true + }).Split(10000) + testFinSeq(t, l) + }) +} + +func TestMap(t *testing.T) { + s := Generate(func(state int) (int, int, bool) { + return state + 1, state + 1, true + }) + + t.Run("inf", func(t *testing.T) { + testInfSeq(t, Map(s, func(i int) int { + return i - 1 + })) + }) + t.Run("fin1", func(t *testing.T) { + testFinSeq(t, Map(s, func(i int) int { + return i - 1 + }).Take(10000)) + }) + t.Run("fin2", func(t *testing.T) { + l, _ := Map(s, func(i int) int { + return i - 1 + }).Split(10000) + testFinSeq(t, l) + }) +} + +func TestStateGen(t *testing.T) { + t.Run("inf", func(t *testing.T) { + var i int + testInfSeq(t, StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + })) + }) + t.Run("fin1", func(t *testing.T) { + var i int + testFinSeq(t, StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + }).Take(10000)) + }) + t.Run("fin2", func(t *testing.T) { + var i int + l, _ := StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + }).Split(10000) + testFinSeq(t, l) + }) +} + +func TestMemo(t *testing.T) { + t.Run("inf", func(t *testing.T) { + var i int + testInfSeq(t, Memo(StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + }))) + }) + t.Run("fin1", func(t *testing.T) { + var i int + testFinSeq(t, Memo(StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + })).Take(10000)) + }) + t.Run("fin2", func(t *testing.T) { + var i int + l, _ := Memo(StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + })).Split(10000) + testFinSeq(t, l) + }) + t.Run("fin3", func(t *testing.T) { + var i int + testFinSeq(t, Memo(StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + }).Take(10000))) + }) + t.Run("fin4", func(t *testing.T) { + var i int + l, _ := StateGen(func() (int, bool) { + ret := i + i++ + return ret, true + }).Split(10000) + testFinSeq(t, Memo(l)) + }) +} diff --git a/stateful_gen.go b/stateful_gen.go new file mode 100644 index 0000000..291e13d --- /dev/null +++ b/stateful_gen.go @@ -0,0 +1,179 @@ +package ion + +import ( + "sync" +) + +type stateGen[T any] struct { + f func() (T, bool) + mems *Vec[T] + m sync.Mutex +} + +func (g *stateGen[T]) Elem(i uint64) (T, bool) { + g.m.Lock() + defer g.m.Unlock() + + memlen := g.mems.Len() + if i >= memlen { + var finished bool + need := i - memlen + 1 + //fmt.Printf("Taking %d new elements.\n", need) + newmems := BuildVec(func(add func(e T)) { + for j := uint64(0); j < need; j++ { + next, cont := g.f() + if !cont { + finished = false + return + } + add(next) + } + finished = true + }) + g.mems = g.mems.Join(newmems) + if !finished { + var r T + return r, false + } + } + // fmt.Printf("g.mems len: %d\n", g.mems.Len()) + // //fmt.Printf("g.mems: %v\n", ToSlice(g.mems)) + // var ii, res int + // g.mems.Iterate(func(e T) bool { + // var ei any + // ei = e + // res += ei.(int) + // ii++ + // if ii == 10000 { + // return false + // } + // return true + // }) + // fmt.Printf("g.mems sum: %d\n", res) + return g.mems.Elem(i) +} + +func (g *stateGen[T]) Split(n uint64) (Seq[T], Seq[T]) { + g.Elem(n) + g.m.Lock() + defer g.m.Unlock() + + //l, r := g.mems.Split(n) + l := g.mems.Take(n) + spl := &splitStateGen[T]{ + g: g, + start: n, + } + return l, spl +} + +func (g *stateGen[T]) Take(n uint64) Seq[T] { + g.Elem(n) + g.m.Lock() + defer g.m.Unlock() + + return g.mems.Take(n) +} + +func (g *stateGen[T]) Iterate(f func(T) bool) { + // TODO: lame only one thread can iterate an immutable struct at a time. + // need to figure this out. + g.m.Lock() + defer g.m.Unlock() + quit := false + g.mems.Iterate(func(e T) bool { + if !f(e) { + quit = true + return false + } + return true + }) + if quit { + return + } + for { + e, cont := g.f() + if !cont { + return + } + g.mems = g.mems.Append(e) + if !f(e) { + return + } + } +} + +func (g *stateGen[T]) Lazy(f func(func() T) bool) { + // TODO: lame only one thread can iterate an immutable seq at a time. + // need to figure this out. + g.m.Lock() + defer g.m.Unlock() + quit := false + g.mems.Lazy(func(ef func() T) bool { + if !f(ef) { + quit = true + return false + } + return true + }) + if quit { + return + } + for { + e, cont := g.f() + if !cont { + return + } + g.mems = g.mems.Append(e) + if !f(func() T { return e }) { + return + } + } +} + +type splitStateGen[T any] struct { + g *stateGen[T] + start uint64 +} + +func (g *splitStateGen[T]) Elem(i uint64) (T, bool) { + return g.g.Elem(g.start + i) +} + +func (g *splitStateGen[T]) Split(n uint64) (Seq[T], Seq[T]) { + ll := g.g.Take(g.start + n) + _, l := ll.Split(g.start) + return l, &splitStateGen[T]{ + g: g.g, + start: g.start + n, + } + +} + +func (g *splitStateGen[T]) Take(n uint64) Seq[T] { + ll := g.g.Take(g.start + n) + _, l := ll.Split(g.start) + return l +} + +func (g *splitStateGen[T]) Iterate(f func(T) bool) { + _, og := g.Split(g.start) + og.Iterate(f) +} + +func (g *splitStateGen[T]) Lazy(f func(func() T) bool) { + _, og := g.Split(g.start) + og.Lazy(f) +} + +// StateGen takes a func `f` and executes it in order to generate +// values of type T in the resulting Seq[T]. +// +// The func `f` should be a clojure containing whatever state it +// needs to generate values. Each call to `f` should generate the +// next element in the sequence. +func StateGen[T any](f func() (T, bool)) Seq[T] { + return &stateGen[T]{ + f: f, + } +} diff --git a/stateful_gen_test.go b/stateful_gen_test.go new file mode 100644 index 0000000..1f6cac9 --- /dev/null +++ b/stateful_gen_test.go @@ -0,0 +1,92 @@ +package ion + +import "testing" + +func TestStateGenSplitElem(t *testing.T) { + i := 0 + seq := StateGen(func() (int, bool) { + ret := i + i += 1 + return ret, true + }) + + if e, ok := seq.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected seq[0] == 0, true, but was %d, %t", e, ok) + } + + l, r := seq.Split(10) + + if e, ok := seq.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected seq[0] == 0, true, but was %d, %t", e, ok) + } + + if e, ok := l.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected l[0] == 0, true, but was %d, %t", e, ok) + } + if e, ok := l.Elem(9); ok == false || e != 9 { + t.Fatalf("Expected l[9] == 9, true, but was %d, %t", e, ok) + } + + if e, ok := r.Elem(0); ok == false || e != 10 { + t.Fatalf("Expected r[0] == 10, true, but was %d, %t", e, ok) + } + + // Must be able to split a stateSplit + ll, rr := r.Split(10) + if e, ok := r.Elem(0); ok == false || e != 10 { + // r should still give correct results even after a split + t.Fatalf("Expected r[0] == 10, true, but was %d, %t", e, ok) + } + if e, ok := ll.Elem(0); ok == false || e != 10 { + t.Fatalf("Expected ll[0] == 10, true, but was %d, %t", e, ok) + } + if e, ok := ll.Elem(9); ok == false || e != 19 { + t.Fatalf("Expected ll[9] == 19, true, but was %d, %t", e, ok) + } + + if e, ok := rr.Elem(0); ok == false || e != 20 { + t.Fatalf("Expected rr[0] == 20, true, but was %d, %t", e, ok) + } + +} + +func TestStateGenTakeElem(t *testing.T) { + i := 0 + seq := StateGen(func() (int, bool) { + ret := i + i += 1 + return ret, true + }) + + if e, ok := seq.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected seq[0] == 0, true, but was %d, %t", e, ok) + } + + l := seq.Take(10) + + if e, ok := seq.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected seq[0] == 0, true, but was %d, %t", e, ok) + } + + if e, ok := l.Elem(0); ok == false || e != 0 { + t.Fatalf("Expected l[0] == 0, true, but was %d, %t", e, ok) + } + if e, ok := l.Elem(9); ok == false || e != 9 { + t.Fatalf("Expected l[9] == 9, true, but was %d, %t", e, ok) + } + + l, r := seq.Split(10) + + // Must be able to Take from a stateSplit + ll := r.Take(10) + if e, ok := r.Elem(0); ok == false || e != 10 { + // r should still give correct results even after a split + t.Fatalf("Expected r[0] == 10, true, but was %d, %t", e, ok) + } + if e, ok := ll.Elem(0); ok == false || e != 10 { + t.Fatalf("Expected ll[0] == 10, true, but was %d, %t", e, ok) + } + if e, ok := ll.Elem(9); ok == false || e != 19 { + t.Fatalf("Expected ll[9] == 19, true, but was %d, %t", e, ok) + } +} diff --git a/testdata/fuzz/FuzzAVLConsistency/8ba3df7bc405cab6 b/testdata/fuzz/FuzzAVLConsistency/8ba3df7bc405cab6 new file mode 100644 index 0000000..08b8513 --- /dev/null +++ b/testdata/fuzz/FuzzAVLConsistency/8ba3df7bc405cab6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000 00000000100000000!0000000020000000070000000080000000000810000000910000000100000000\xf900000000200000000\xb000000000\xb300000000A10000000B10000000700000000\xe800000000\xda00000000800000000 0000000090000000181000000") diff --git a/testdata/fuzz/FuzzAVLConsistency/a6c8b5d8a4c4a7b0 b/testdata/fuzz/FuzzAVLConsistency/a6c8b5d8a4c4a7b0 new file mode 100644 index 0000000..44a7208 --- /dev/null +++ b/testdata/fuzz/FuzzAVLConsistency/a6c8b5d8a4c4a7b0 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000A00000000800000000\xec00000000\xf300000000\xb500000000\x9300000000\xb210000000010000000B00000000\xc400000000~00000000B10000000010000000\xdc00000000710000000\xeb10000000000000000x10000000C00000000y00000000\xf700000000C10000000X10000000X10000000010000000\xdd00000000\x9f00000001710000000900000000\x1100000000\x8600000000700000000\xd800000000\x7f00000000u00000000a00000000010000000A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzAVLInsDel/c4c80dfabea610b4 b/testdata/fuzz/FuzzAVLInsDel/c4c80dfabea610b4 new file mode 100644 index 0000000..97da36d --- /dev/null +++ b/testdata/fuzz/FuzzAVLInsDel/c4c80dfabea610b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000100000000000000000000000") diff --git a/testdata/fuzz/FuzzAVLInsDel/f95dad931689e2b2 b/testdata/fuzz/FuzzAVLInsDel/f95dad931689e2b2 new file mode 100644 index 0000000..a2a4a4b --- /dev/null +++ b/testdata/fuzz/FuzzAVLInsDel/f95dad931689e2b2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0\x00\x00\x00\x00\x00\x00\x00\x00000000000000000000000000000") diff --git a/testdata/fuzz/FuzzRBConsistency/20c5fa90ef35db0c b/testdata/fuzz/FuzzRBConsistency/20c5fa90ef35db0c new file mode 100644 index 0000000..6f1b144 --- /dev/null +++ b/testdata/fuzz/FuzzRBConsistency/20c5fa90ef35db0c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("010 \x00\x00\x00\x00\x00000 \x00\x00\x00\x00\x000000000000000000010\x00\x000\x00\x00\x00\x00\x000000000021\x00\x000\x00\x00\x00\x00\x00") diff --git a/testdata/fuzz/FuzzRBConsistency/427c7736bcf46155 b/testdata/fuzz/FuzzRBConsistency/427c7736bcf46155 new file mode 100644 index 0000000..76a201a --- /dev/null +++ b/testdata/fuzz/FuzzRBConsistency/427c7736bcf46155 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("100000000") diff --git a/testdata/fuzz/FuzzRBConsistency/6507bdc0b67082cb b/testdata/fuzz/FuzzRBConsistency/6507bdc0b67082cb new file mode 100644 index 0000000..f935cf0 --- /dev/null +++ b/testdata/fuzz/FuzzRBConsistency/6507bdc0b67082cb @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000\xb900000000100000000\xc900000000\xfa00000000\xb510000000210000000200000000Y00000000Z00000000200000000\xfc00000000a100000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzRBConsistency/d730c13962ecd673 b/testdata/fuzz/FuzzRBConsistency/d730c13962ecd673 new file mode 100644 index 0000000..4e5c5c8 --- /dev/null +++ b/testdata/fuzz/FuzzRBConsistency/d730c13962ecd673 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000010\x00\x00\x00\x00\x00\x00\x00\x000000000021\x00\x00\x00\x00\x00\x00\x00\x00") diff --git a/testdata/fuzz/FuzzRBInsDel/015f58224ce50196 b/testdata/fuzz/FuzzRBInsDel/015f58224ce50196 new file mode 100644 index 0000000..a3c7e79 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/015f58224ce50196 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("10000000000000000100000000 00000000!") diff --git a/testdata/fuzz/FuzzRBInsDel/0b17e90b730095f1 b/testdata/fuzz/FuzzRBInsDel/0b17e90b730095f1 new file mode 100644 index 0000000..4b5404a --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/0b17e90b730095f1 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000\x01\x00\x00\x000001") diff --git a/testdata/fuzz/FuzzRBInsDel/0d485703d33cd7a4 b/testdata/fuzz/FuzzRBInsDel/0d485703d33cd7a4 new file mode 100644 index 0000000..bb99217 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/0d485703d33cd7a4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000001") diff --git a/testdata/fuzz/FuzzRBInsDel/1802d385a092b0ca b/testdata/fuzz/FuzzRBInsDel/1802d385a092b0ca new file mode 100644 index 0000000..da4ee89 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/1802d385a092b0ca @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\xdd,J\x9a\xf9D\x1b'd\xb2%(k\r\xe5\xe80\xd2\x1b\xd7r\x01nhy\xd6\x1f\x8b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") diff --git a/testdata/fuzz/FuzzRBInsDel/22066065382db638 b/testdata/fuzz/FuzzRBInsDel/22066065382db638 new file mode 100644 index 0000000..7cb8f1a --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/22066065382db638 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("1000000000000000010") diff --git a/testdata/fuzz/FuzzRBInsDel/700c9ee9ba4157a7 b/testdata/fuzz/FuzzRBInsDel/700c9ee9ba4157a7 new file mode 100644 index 0000000..767744e --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/700c9ee9ba4157a7 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("10000000\xd110000000a10000000010000000\xfb00000000b00000000c10000000110000000200000000700000000x00000000y00000000z00000000\xc5") diff --git a/testdata/fuzz/FuzzRBInsDel/79e7173719db76d6 b/testdata/fuzz/FuzzRBInsDel/79e7173719db76d6 new file mode 100644 index 0000000..dbacb96 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/79e7173719db76d6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000a0aaaaaaaa000000000000000 00") diff --git a/testdata/fuzz/FuzzRBInsDel/ca7f6d445caeeb9e b/testdata/fuzz/FuzzRBInsDel/ca7f6d445caeeb9e new file mode 100644 index 0000000..bbc8bc4 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/ca7f6d445caeeb9e @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000\xea00000000x00000000y00000000\xb300000000100000000z00000000200000000700000000\x8c00000000\xb1") diff --git a/testdata/fuzz/FuzzRBInsDel/cad981f17b94cfec b/testdata/fuzz/FuzzRBInsDel/cad981f17b94cfec new file mode 100644 index 0000000..2936139 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/cad981f17b94cfec @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000001000000002000000000") diff --git a/testdata/fuzz/FuzzRBInsDel/ce9602d68af5511c b/testdata/fuzz/FuzzRBInsDel/ce9602d68af5511c new file mode 100644 index 0000000..6b2181b --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/ce9602d68af5511c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000100000000200000000 ") diff --git a/testdata/fuzz/FuzzRBInsDel/df0e89e9c47340a6 b/testdata/fuzz/FuzzRBInsDel/df0e89e9c47340a6 new file mode 100644 index 0000000..4d1eb80 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/df0e89e9c47340a6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00)p000\x00\x00\x00\x7f0\x1800001") diff --git a/testdata/fuzz/FuzzRBInsDel/e5a19720b32e7627 b/testdata/fuzz/FuzzRBInsDel/e5a19720b32e7627 new file mode 100644 index 0000000..e1afbb5 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/e5a19720b32e7627 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000X0000000000000000000100000000200") diff --git a/testdata/fuzz/FuzzRBInsDel/f2c87a26a4e2f46a b/testdata/fuzz/FuzzRBInsDel/f2c87a26a4e2f46a new file mode 100644 index 0000000..6fbc961 --- /dev/null +++ b/testdata/fuzz/FuzzRBInsDel/f2c87a26a4e2f46a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000\x00\v0000000000 \v\v\v\v\v\v\v000000010000000001000000020") diff --git a/vec.go b/vec.go new file mode 100644 index 0000000..3c29558 --- /dev/null +++ b/vec.go @@ -0,0 +1,729 @@ +package ion + +import ( + "fmt" + "io" + "os" +) + +const spanSize = 64 + +// Vec is a sequence of elements of type T. It is constructed internally +// of spans connected in a somewhat balanced tree structure. +// +// Vec is immutable, meaning operations performed on it return +// new Vecs without modifying the old. Because of the immutable nature +// of the structure, the new Vec shares most of its memory with the +// original, meaning operations can be performed efficiently without +// needing to reconstruct an entirely new vec for every operation. +type Vec[T any] struct { + leftCount uint64 + height int8 + l interface{} // *Vec | *seqLeaf + r interface{} // *Vec | *seqLeaf +} + +// BuildVec constructs a Vec in an efficient way. It accepts a function, +// `f`, which it executes, passing `f` a function `add`. +// The function `add` can be called repeatedly within the body of `f` in +// order to progressively append elements to the Vec. +// +// For example: +// +// BuildVec(func(add func(int)) { +// for i := 0; i < 100; i++ { +// add(i) +// } +// }) +// +// This is more efficient than simply Appending to a Vec in a loop. +func BuildVec[T any](f func(add func(T))) *Vec[T] { + var s *Vec[T] + f(func(e T) { + s = s.mutAppend(e) + }) + return s +} + +func (s *Vec[T]) duplicate() *Vec[T] { + return &Vec[T]{ + leftCount: s.leftCount, + height: s.height, + l: s.l, + r: s.r, + } +} + +func newLeaf[T any]() *seqLeaf[T] { + l := &seqLeaf[T]{} + l.seq = l.is[:0] + return l +} + +// Len returns the number of elements in the Vec +func (s *Vec[T]) Len() uint64 { + if s == nil { + return 0 + } + if s.r == nil { + return s.leftCount + } + + switch o := s.r.(type) { + case *Vec[T]: + return s.leftCount + o.Len() + case *seqLeaf[T]: + return s.leftCount + uint64(len(o.seq)) + default: + panic("BAD TYPE") + } +} + +// Elem implements Seq +func (s *Vec[T]) Elem(idx uint64) (T, bool) { + // defer func() { + // if p := recover(); p != nil { + // f, _ := os.Create("out.dot") + // s.Dot(f) + // f.Close() + // panic(p) + // } + // }() + // fmt.Printf("ELEM %d, LEN: %d\n", idx, s.Len()) + // if idx >= s.Len() { + // panic(fmt.Sprintf("Index %d Out of bounds for Vec of length %d", idx, s.Len())) + // } + // //s.Dot(os.Stdout) + // if s2 := validateVec(s); s2 != nil { + // panic("OH NO!\n") + // } + return s.elem(idx) +} + +func (s *Vec[T]) elem(idx uint64) (T, bool) { + if s == nil { + var r T + return r, false + //panic(fmt.Sprintf("Index %d Out of bounds for Vec of length %d", idx, s.Len())) + } + if uint64(idx) >= s.leftCount { + idx -= s.leftCount + if s.r == nil { + var r T + return r, false + panic("Out of bounds") + } + switch o := s.r.(type) { + case *Vec[T]: + return o.elem(idx) + case *seqLeaf[T]: + if idx >= uint64(len(o.seq)) { + //s.Dot(os.Stdout) + var r T + return r, false + } + return o.seq[idx], true + default: + panic("Bad Type") + } + } else { + switch o := s.l.(type) { + case *Vec[T]: + return o.elem(idx) + case *seqLeaf[T]: + return o.seq[idx], true + default: + panic("Bad Type") + } + } +} + +// Iterate implements Seq +func (s *Vec[T]) Iterate(f func(T) bool) { + s.iterate(f) +} + +func (s *Vec[T]) iterate(f func(T) bool) bool { + if s == nil { + return true + } + if s.l != nil { + switch o := s.l.(type) { + case *Vec[T]: + if !o.iterate(f) { + return false + } + case *seqLeaf[T]: + for _, e := range o.seq { + if !f(e) { + return false + } + } + } + } + if s.r != nil { + switch o := s.r.(type) { + case *Vec[T]: + if !o.iterate(f) { + return false + } + case *seqLeaf[T]: + for _, e := range o.seq { + if !f(e) { + return false + } + } + } + } + return true +} + +// Lazy implements Seq +func (s *Vec[T]) Lazy(f func(func() T) bool) { + s.lazy(f) +} +func (s *Vec[T]) lazy(f func(func() T) bool) bool { + if s == nil { + return true + } + if s.l != nil { + switch o := s.l.(type) { + case *Vec[T]: + if !o.lazy(f) { + return false + } + case *seqLeaf[T]: + for _, e := range o.seq { + e := e + if !f(func() T { return e }) { + return false + } + } + } + } + if s.r != nil { + switch o := s.r.(type) { + case *Vec[T]: + if !o.lazy(f) { + return false + } + case *seqLeaf[T]: + for _, e := range o.seq { + e := e + if !f(func() T { return e }) { + return false + } + } + } + } + return true +} + +func (s *Vec[T]) mutRebalance() *Vec[T] { + if bf := s.l.(*Vec[T]).height - s.r.(*Vec[T]).height; bf < -2 { + // right is taller + r := s.r.(*Vec[T]).duplicate() + newLeftCount := s.leftCount + r.leftCount + s.r = r.l + r.l = s + r.leftCount = newLeftCount + s = r + } else if bf > 2 { + // left is taller + l := s.l.(*Vec[T]).duplicate() + s.l = l.r + s.leftCount = s.l.(*Vec[T]).Len() + l.r = s + s = l + } + return s +} + +// Join returns a new Vec[T] that is the contents of the original +// Vec[T] followed by `s2`. +func (s *Vec[T]) Join(s2 *Vec[T]) *Vec[T] { + if s == nil { + return s2 + } else if s2 == nil { + return s + } + + if bf := s.height - s2.height; bf < -1 { + //fmt.Printf("Rebalance Right.\n") + // s2 is taller + // ignore for now. + s2 = s2.duplicate() + s2.l = s.Join(s2.l.(*Vec[T])) + s2.leftCount = s2.l.(*Vec[T]).Len() // TODO: This is inefficient + s2 = s2.mutRebalance() + s2.reheight() + return s2 + } else if bf > 1 { + //fmt.Printf("Rebalance Left.\n") + // s is taller + s = s.duplicate() + s.r = s.r.(*Vec[T]).Join(s2) + s = s.mutRebalance() + s.reheight() + return s + } + + if s.height == 1 && s2.height == 1 { + // these both have leaf nodes as children. Let's see if we can merge them. + total := s.Len() + s2.Len() + if total <= spanSize*2 { + // These can fit into a single node. + + // TODO: This is terribly inefficient. Just a POC + var ns *Vec[T] + s.Iterate(func(i T) bool { + ns = ns.Append(i) + return true + }) + s2.Iterate(func(i T) bool { + ns = ns.Append(i) + return true + }) + return ns + } + } + + ns := &Vec[T]{ + leftCount: s.Len(), + l: s, + r: s2, + } + ns.reheight() + return ns +} + +// Split implements Seq +func (s *Vec[T]) Split(idx uint64) (Seq[T], Seq[T]) { + var ls, rs Seq[T] + ls, rs = s.split(idx) + return ls, rs +} + +// Take implements Seq +func (s *Vec[T]) Take(idx uint64) Seq[T] { + // TODO: Don't do the extra work of allocating the rs. + var ls Seq[T] + if idx >= s.Len() { + return s + } + ls, _ = s.split(idx) + return ls +} + +func (s *Vec[T]) split(idx uint64) (*Vec[T], *Vec[T]) { + if s == nil { + return (*Vec[T])(nil), (*Vec[T])(nil) + //panic(fmt.Sprintf("Index %d Out of bounds for Vec of length %d", idx, s.Len())) + } + if uint64(idx) >= s.leftCount { + idx -= s.leftCount + if s.r == nil { + // TODO: This still allocates in the lower stack frames, when we don't need to + return s, (*Vec[T])(nil) + //panic("Out of bounds") + } + switch o := s.r.(type) { + case *Vec[T]: + s = s.duplicate() + l, r := o.split(idx) + s.r = r + + var sl *Vec[T] + switch o := s.l.(type) { + case *Vec[T]: + sl = o + case *seqLeaf[T]: + panic("This should not be possible.") + for _, e := range o.seq { + fmt.Printf("2Adding %v to pre\n", e) + sl = sl.Append(e) + } + } + sl = sl.Join(l) + + // l.Iterate(func(i uint64) { + // //fmt.Printf("BEFORE:\n") + // //sl.Dot(os.Stdout) + // fmt.Printf("3Adding %d to pre\n", i) + // sl = sl.Append(i) + // //sl.Dot(os.Stdout) + // }) + return sl, r + case *seqLeaf[T]: + left := s.duplicate() + if idx == 0 { + right := s.duplicate() + right.l = right.r + right.r = nil + left.r = nil + right.leftCount = uint64(len(right.l.(*seqLeaf[T]).seq)) + return left, right + } + + lo := o.clone() + if idx >= uint64(len(lo.seq)) { + return s, nil + } + lo.seq = lo.seq[:idx] + left.r = lo + + ro := o.clone() + ro.mutCutFront(idx) + right := &Vec[T]{ + leftCount: uint64(len(ro.seq)), + height: 1, + l: ro, + } + return left, right + default: + panic("Bad Type") + } + } else { + switch o := s.l.(type) { + case *Vec[T]: + s = s.duplicate() + sl, sr := o.split(idx) + s.l = sr + s.leftCount -= idx + return sl, s + case *seqLeaf[T]: + if idx == 0 { + return nil, s + } + right := s.duplicate() + ro := o.clone() + ro.mutCutFront(idx) + right.l = ro + right.leftCount = uint64(len(ro.seq)) + + lo := o.clone() + lo.seq = lo.seq[:idx] + left := &Vec[T]{ + leftCount: uint64(len(lo.seq)), + height: 1, + l: lo, + } + return left, right + default: + fmt.Printf("VAL: %#v\n", s.l) + s.Dot(os.Stdout) + panic("Bad Type") + } + } +} + +// Dot writes out a graphviz dot formatted directed graph to +// the writer `w`. This can be used with graphviz to visualize +// the tree's internal structure. +func (s *Vec[T]) Dot(w io.Writer) { + fmt.Fprintf(w, "digraph {\n") + s.dotr(w) + fmt.Fprintf(w, "}\n") +} + +func (s *Vec[T]) dotr(w io.Writer) { + if s == nil { + return + } + fmt.Fprintf(w, "\t%#p [label=\"left: %d, height: %d\"];\n", + s, s.leftCount, s.height) + if s.l != nil { + switch o := s.l.(type) { + case *Vec[T]: + fmt.Fprintf(w, "\t%#p -> %#p;\n", s, o) + o.dotr(w) + case *seqLeaf[T]: + fmt.Fprintf(w, "\t%#p -> %#p;\n", s, o) + fmt.Fprintf(w, "\t%#p [label=\"%v\"];\n", o, o.seq) + default: + panic("BAD TYPE") + + } + } else { + fmt.Fprintf(w, "\t%#p -> %#pln;\n", s, s) + fmt.Fprintf(w, "\t%#pln [label=\"null\"];\n", s) + } + if s.r != nil { + switch o := s.r.(type) { + case *Vec[T]: + fmt.Fprintf(w, "\t%#p -> %#p;\n", s, o) + o.dotr(w) + case *seqLeaf[T]: + fmt.Fprintf(w, "\t%#p -> %#p;\n", s, o) + fmt.Fprintf(w, "\t%#p [label=\"%v\"];\n", o, o.seq) + default: + panic("BAD TYPE") + + } + } else { + fmt.Fprintf(w, "\t%#p -> %#pln;\n", s, s) + fmt.Fprintf(w, "\t%#pln [label=\"null\"];\n", s) + } +} + +func (t *Vec[T]) reheight() { + if t.l != nil && t.r != nil { + if l, ok := t.l.(*Vec[T]); ok { + r := t.r.(*Vec[T]) + t.height = max(l.height, r.height) + 1 + return + } + } + t.height = 1 +} + +// Append returns a new list containing the elements of the original Vec[T] +// with i appended to the end. +func (s *Vec[T]) Append(i T) *Vec[T] { + //fmt.Printf("Appending %d\n", i) + if s == nil { + l := newLeaf[T]() + l.seq = append(l.seq, i) + return &Vec[T]{ + leftCount: 1, + height: 1, + l: l, + } + } + if s.r != nil { + s = s.duplicate() + switch o := s.r.(type) { + case *Vec[T]: + s.r = o.Append(i) + sl := s.l.(*Vec[T]) + if s.r.(*Vec[T]).height > sl.height { + sl = sl.duplicate() + s.l = sl + s.l = &Vec[T]{ + leftCount: s.leftCount, + height: sl.height + 1, + l: s.l, + r: s.r.(*Vec[T]).l, + } + s.leftCount += s.r.(*Vec[T]).leftCount + sl.reheight() + s.r = s.r.(*Vec[T]).r + } + s.reheight() + case *seqLeaf[T]: + if len(o.seq) == spanSize { + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.r = &Vec[T]{ + leftCount: 1, + height: 1, + l: l, + } + s.l = &Vec[T]{ + leftCount: s.leftCount, + height: 1, + l: s.l, + r: o, + } + s.leftCount += spanSize + s.height = 2 + } else { + o.seq = append(o.seq, i) + } + default: + panic("BAD TYPE") + } + return s + } else if s.l != nil { + s = s.duplicate() + switch o := s.l.(type) { + case *Vec[T]: + s.l = o.Append(i) + s.reheight() + s.leftCount++ + case *seqLeaf[T]: + if len(o.seq) == spanSize { + // s.r must be nil, so we should add a seq to s.r + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.r = l + } else { + o = o.clone() + o.seq = append(o.seq, i) + s.l = o + s.leftCount++ + } + default: + panic("BAD TYPE") + } + return s + } else { + s = s.duplicate() + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.l = l + s.leftCount = 1 + return s + } + panic("BAD") +} + +func (s *Vec[T]) mutAppend(i T) *Vec[T] { + if s == nil { + l := newLeaf[T]() + l.seq = append(l.seq, i) + return &Vec[T]{ + leftCount: 1, + height: 1, + l: l, + } + } + if s.r != nil { + //s = s.duplicate() + switch o := s.r.(type) { + case *Vec[T]: + s.r = o.mutAppend(i) + sl := s.l.(*Vec[T]) + if s.r.(*Vec[T]).height > sl.height { + //sl = sl.duplicate() + //s.l = sl + s.l = &Vec[T]{ + leftCount: s.leftCount, + height: sl.height + 1, + l: s.l, + r: s.r.(*Vec[T]).l, + } + s.leftCount += s.r.(*Vec[T]).leftCount + sl.reheight() + s.r = s.r.(*Vec[T]).r + } + s.reheight() + case *seqLeaf[T]: + if len(o.seq) == spanSize { + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.r = &Vec[T]{ + leftCount: 1, + height: 1, + l: l, + } + s.l = &Vec[T]{ + leftCount: s.leftCount, + height: 1, + l: s.l, + r: o, + } + s.leftCount += spanSize + s.height = 2 + } else { + o.seq = append(o.seq, i) + } + default: + panic("BAD TYPE") + } + return s + } else if s.l != nil { + //s = s.duplicate() + switch o := s.l.(type) { + case *Vec[T]: + s.l = o.mutAppend(i) + s.reheight() + s.leftCount++ + case *seqLeaf[T]: + if len(o.seq) == spanSize { + // s.r must be nil, so we should add a seq to s.r + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.r = l + } else { + //o = o.clone() + o.seq = append(o.seq, i) + s.l = o + s.leftCount++ + } + default: + panic("BAD TYPE") + } + return s + } else { + //s = s.duplicate() + l := newLeaf[T]() + l.seq = append(l.seq, i) + s.l = l + s.leftCount = 1 + return s + } + panic("BAD") +} + +type seqLeaf[T any] struct { + seq []T + is [spanSize]T +} + +func (s *seqLeaf[T]) clone() *seqLeaf[T] { + l := &seqLeaf[T]{} + *l = *s + l.seq = l.is[:len(s.seq)] + return l +} + +// This function trims a leaf by moving its elements. +// This mutates the VecLeaf so should only be used when +// it is appropriate, e.g. when constructing new values. +func (s *seqLeaf[T]) mutCutFront(idx uint64) { + s2 := s.seq[idx:] + s.seq = s.is[:len(s2)] + copy(s.seq, s2) +} + +func validateVec[T any](s *Vec[T]) *Vec[T] { + if s == nil { + return nil + } + if _, ok := s.l.(*seqLeaf[T]); ok { + // if s's l is a leaf, s's right must be a leaf. + if s.r != nil { + if _, ok := s.r.(*seqLeaf[T]); !ok { + fmt.Printf("BAD NODE! Left is leaf, right is not leaf.\n") + return s + } + } + } else { + if s.r != nil { + if _, ok := s.r.(*seqLeaf[T]); ok { + fmt.Printf("BAD NODE! Left is seq, right is leaf.\n") + return s + } + } + } + + switch o := s.l.(type) { + case *Vec[uint64]: + if s.leftCount != o.Len() { + fmt.Printf("EXPECTED LEFTCOUNT == %d, but was %d\n", o.Len(), s.leftCount) + return s + } + case *seqLeaf[uint64]: + if s.leftCount != uint64(len(o.seq)) { + fmt.Printf("(leaf) EXPECTED LEFTCOUNT == %d, but was %d\n", len(o.seq), s.leftCount) + return s + } + } + + if s.l != nil { + if sl, ok := s.l.(*Vec[T]); ok { + if bad := validateVec(sl); bad != nil { + return bad + } + } + } + if s.r != nil { + if sr, ok := s.r.(*Vec[T]); ok { + if bad := validateVec(sr); bad != nil { + return bad + } + } + } + return nil +} diff --git a/vec_test.go b/vec_test.go new file mode 100644 index 0000000..6889dae --- /dev/null +++ b/vec_test.go @@ -0,0 +1,308 @@ +package ion + +import ( + "io" + "math/rand" + "os" + "testing" +) + +// func TestVecAppend(t *testing.T) { +// var s *Vec + +// s = s.Append(1) +// s = s.Append(2) +// s = s.Append(3) +// spew.Dump(s) + +// s = s.Append(4) +// s = s.Append(5) +// s = s.Append(6) +// spew.Dump(s) + +// s = s.Append(7) +// s = s.Append(8) +// spew.Dump(s) + +// s = s.Append(9) +// spew.Dump(s) +// for i := uint64(10); i < 17; i++ { +// s = s.Append(i) +// } +// spew.Dump(s) +// s = s.Append(17) +// fmt.Printf("BREAK\n") +// s.Dot(os.Stdout) + +// for i := uint64(18); i <= 33; i++ { +// s = s.Append(i) +// } +// s.Dot(os.Stdout) +// } + +// func TestVecBigJoin(t *testing.T) { +// var s *Vec[uint64] +// for i := uint64(0); i < 1800; i++ { +// //writeDot(s, "out.dot") +// var s2 *Vec[uint64] +// s2 = s2.Append(i) +// //writeDot(s2, "out2.dot") +// s = s2.Join(s) +// //writeDot(s, "out3.dot") +// } +// writeDot(s, "out3.dot") +// } + +func TestVecAppend(t *testing.T) { + var s *Vec[uint64] + for i := uint64(0); i < 20; i++ { + s = s.Append(i) + } + + s2 := s + for i := uint64(20); i < 40; i++ { + s2 = s2.Append(i) + } + + for i := uint64(0); i < 40; i++ { + e, ok := s2.Elem(i) + if !ok || e != i { + t.Fatalf("Expected element at index %d to be %d, but got %d.\n", i, i, e) + } + } + + //s.Elem(30) + if l := s.Len(); l != 20 { + t.Fatalf("Expected s to have length 20, but has length %d\n", l) + } + + if l := s2.Len(); l != 40 { + t.Fatalf("Expected s2 to have length 40, but has length %d\n", l) + } +} + +// func TestVecSplit(t *testing.T) { +// var s *Vec[uint64] +// for i := uint64(0); i < 32; i++ { +// s = s.Append(i) +// } + +// f, _ := os.Create("out2.dot") +// s.Dot(f) +// f.Close() + +// s1, s2 := s.split(25) +// f, _ = os.Create("out3.dot") +// s1.Dot(f) +// f.Close() + +// f, _ = os.Create("out4.dot") +// s2.Dot(f) +// f.Close() +// } + +func TestVecJoin(t *testing.T) { + var s1, s2 *Vec[uint64] + + for i := uint64(0); i < 20; i++ { + s1 = s1.Append(i) + s2 = s2.Append(i) + } + + s3 := s1.Join(s2) + + if l := s3.Len(); l != 40 { + t.Fatalf("Expected length of 40 but was %d\n", l) + } + + // f, _ := os.Create("out2.dot") + // s1.Dot(f) + // f.Close() + + // f, _ = os.Create("out3.dot") + // s2.Dot(f) + // f.Close() + + // f, _ = os.Create("out4.dot") + // s3.Dot(f) + // f.Close() +} + +func TestVecSplitJoinSingle(t *testing.T) { + t.Run("prepend", func(t *testing.T) { + var s *Vec[uint64] + var sl []uint64 + for i := uint64(0); i < 20; i++ { + s = s.Append(i) + sl = append(sl, i) + } + + v := func(s *Vec[uint64]) { + if bad := validateVec(s); bad != nil { + s.Dot(os.Stdout) + t.Fatalf("Failed to validate sequence.\n") + } + } + + v(s) + + for i := 0; i < 400; i++ { + l, r := s.split(1) + s = r.Join(l) + v(s) + sl = append(sl[1:], sl[:1]...) + sliceEqual(t, asSlice(s), sl) + } + }) + t.Run("append", func(t *testing.T) { + var s *Vec[uint64] + var sl []uint64 + for i := uint64(0); i < 20; i++ { + s = s.Append(i) + sl = append(sl, i) + } + + v := func(s *Vec[uint64]) { + if bad := validateVec(s); bad != nil { + s.Dot(os.Stdout) + t.Fatalf("Failed to validate sequence.\n") + } + } + + v(s) + + for i := 0; i < 400; i++ { + l, r := s.split(19) + s = r.Join(l) + v(s) + sl = append(sl[19:], sl[:19]...) + sliceEqual(t, asSlice(s), sl) + } + }) +} + +func TestVecBuild(t *testing.T) { + s := BuildVec[int](func(add func(e int)) { + for i := 0; i < 100; i++ { + add(i) + } + }) + //TODO: finish test + s.Dot(io.Discard) +} + +func TestVecSplitJoinRandom(t *testing.T) { + rand.Seed(1000) + var s *Vec[uint64] + var sl []uint64 + for i := uint64(0); i < 20; i++ { + s = s.Append(i) + sl = append(sl, i) + } + + v := func(s *Vec[uint64]) { + if bad := validateVec(s); bad != nil { + s.Dot(os.Stdout) + t.Fatalf("Failed to validate sequence.\n") + } + } + + v(s) + + var sum uint64 + s.Iterate(func(i uint64) bool { + sum += i + return true + }) + + //fmt.Printf("SUM: %d\n", sum) + //return + + for i := 0; i < 10000; i++ { + //fmt.Printf("SEQ : %v\nSLICE: %v\n", asSlice(s), sl) + //fmt.Printf("LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOp\n") + rnd := rand.Uint64() % 20 + //fmt.Printf("SPLITTING AT %d\n", + // rnd) + //s.Dot(os.Stdout) + //writeDot(s, "out.dot") + l, r := s.split(rnd) + sll := sl[:rnd] + slr := sl[rnd:] + sliceEqual(t, asSlice(l), sll) + sliceEqual(t, asSlice(r), slr) + + //fmt.Printf("Validating L:\n") + //l.Dot(os.Stdout) + //writeDot(l, "out2.dot") + v(l) + //fmt.Printf("##########################\n") + + //fmt.Printf("Validating R:\n") + //r.Dot(os.Stdout) + //writeDot(r, "out3.dot") + v(r) + //fmt.Printf("##########################\n") + + //fmt.Printf("JOINING:\n") + s = r.Join(l) + sl = append(slr, sll...) + sliceEqual(t, asSlice(s), sl) + + //fmt.Printf("Validating S:\n") + //s.Dot(os.Stdout) + //writeDot(s, "out4.dot") + v(s) + + newsum := uint64(0) + s.Iterate(func(j uint64) bool { + newsum += j + return true + }) + if newsum != sum { + t.Fatalf("On iteration %d: expected sum to be %d, but was %d\n", i, sum, newsum) + } + } + //fmt.Printf("SEQ : %v\nSLICE: %v\n", asSlice(s), sl) + //s.Dot(os.Stdout) + //writeDot(s, "out.dot") +} + +func sliceEqual(t *testing.T, s, s2 []uint64) { + if len(s) != len(s2) { + t.Fatalf("%v != %v", s, s2) + } + for i := range s { + if s[i] != s2[i] { + t.Fatalf("%v != %v at index %d", s, s2, i) + } + } +} + +func asSlice(s *Vec[uint64]) []uint64 { + var sl []uint64 + s.Iterate(func(i uint64) bool { + sl = append(sl, i) + return true + }) + return sl +} + +func writeDot(s *Vec[uint64], name string) { + f, _ := os.Create(name) + defer f.Close() + s.Dot(f) +} + +func TestVecLeafCut(t *testing.T) { + s := newLeaf[uint64]() + s.seq = append(s.seq, 1) + s.seq = append(s.seq, 2) + s.seq = append(s.seq, 3) + s.seq = append(s.seq, 4) + s.mutCutFront(2) + + if s.is[0] != 3 { + t.Fatalf("cutting the leaf failed.") + } +}