Add chunk implementation from old code base
This commit is contained in:
parent
a5a78c786a
commit
4f811a8ffe
|
@ -0,0 +1,66 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// chunk holds the offsets for a partial piece of data
|
||||
type chunk struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
}
|
||||
|
||||
// Size returns the number of bytes between Start and End.
|
||||
func (c chunk) Size() int64 {
|
||||
return c.End - c.Start + 1
|
||||
}
|
||||
|
||||
// chunkSet holds a set of chunks and helps with adding/merging new chunks into
|
||||
// set set.
|
||||
type chunkSet []chunk
|
||||
|
||||
// Add merges a newChunk into a chunkSet. This may lead to the chunk being
|
||||
// combined with one or more adjecent chunks, possibly shrinking the chunkSet
|
||||
// down to a single member.
|
||||
func (c *chunkSet) Add(newChunk chunk) {
|
||||
if newChunk.Size() <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
*c = append(*c, newChunk)
|
||||
sort.Sort(c)
|
||||
|
||||
// merge chunks that can be combined
|
||||
for i := 0; i < len(*c)-1; i++ {
|
||||
current := (*c)[i]
|
||||
next := (*c)[i+1]
|
||||
|
||||
if current.End+1 < next.Start {
|
||||
continue
|
||||
}
|
||||
|
||||
*c = append((*c)[0:i], (*c)[i+1:]...)
|
||||
|
||||
if current.End > next.End {
|
||||
(*c)[i].End = current.End
|
||||
}
|
||||
|
||||
if current.Start < next.Start {
|
||||
(*c)[i].Start = current.Start
|
||||
}
|
||||
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
func (c chunkSet) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c chunkSet) Less(i, j int) bool {
|
||||
return c[i].Start < c[j].Start
|
||||
}
|
||||
|
||||
func (c chunkSet) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var chunkSet_AddTests = []struct {
|
||||
Name string
|
||||
Add []chunk
|
||||
Expect []chunk
|
||||
}{
|
||||
{
|
||||
Name: "add one",
|
||||
Add: []chunk{{Start: 1, End: 5}},
|
||||
Expect: []chunk{{Start: 1, End: 5}},
|
||||
},
|
||||
{
|
||||
Name: "add twice",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 1, End: 5}},
|
||||
Expect: []chunk{{Start: 1, End: 5}},
|
||||
},
|
||||
{
|
||||
Name: "append",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 7, End: 10}},
|
||||
Expect: []chunk{{Start: 1, End: 5}, {Start: 7, End: 10}},
|
||||
},
|
||||
{
|
||||
Name: "insert",
|
||||
Add: []chunk{{Start: 0, End: 5}, {Start: 12, End: 15}, {Start: 7, End: 10}},
|
||||
Expect: []chunk{{Start: 0, End: 5}, {Start: 7, End: 10}, {Start: 12, End: 15}},
|
||||
},
|
||||
{
|
||||
Name: "prepend",
|
||||
Add: []chunk{{Start: 5, End: 10}, {Start: 1, End: 3}},
|
||||
Expect: []chunk{{Start: 1, End: 3}, {Start: 5, End: 10}},
|
||||
},
|
||||
{
|
||||
Name: "grow start",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 0, End: 5}},
|
||||
Expect: []chunk{{Start: 0, End: 5}},
|
||||
},
|
||||
{
|
||||
Name: "grow end",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 1, End: 6}},
|
||||
Expect: []chunk{{Start: 1, End: 6}},
|
||||
},
|
||||
{
|
||||
Name: "grow end with multiple items",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 7, End: 10}, {Start: 8, End: 15}},
|
||||
Expect: []chunk{{Start: 1, End: 5}, {Start: 7, End: 15}},
|
||||
},
|
||||
{
|
||||
Name: "grow exact end match",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 6, End: 6}},
|
||||
Expect: []chunk{{Start: 1, End: 6}},
|
||||
},
|
||||
{
|
||||
Name: "sink",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 2, End: 3}},
|
||||
Expect: []chunk{{Start: 1, End: 5}},
|
||||
},
|
||||
{
|
||||
Name: "swallow",
|
||||
Add: []chunk{{Start: 1, End: 5}, {Start: 6, End: 10}, {Start: 0, End: 11}},
|
||||
Expect: []chunk{{Start: 0, End: 11}},
|
||||
},
|
||||
{
|
||||
Name: "ignore 0 byte chunks",
|
||||
Add: []chunk{{Start: 0, End: -1}},
|
||||
Expect: []chunk{},
|
||||
},
|
||||
{
|
||||
Name: "ignore invalid chunks",
|
||||
Add: []chunk{{Start: 0, End: -2}},
|
||||
Expect: []chunk{},
|
||||
},
|
||||
}
|
||||
|
||||
func Test_chunkSet_Add(t *testing.T) {
|
||||
for _, test := range chunkSet_AddTests {
|
||||
var chunks chunkSet
|
||||
for _, chunk := range test.Add {
|
||||
chunks.Add(chunk)
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf("%+v", test.Expect)
|
||||
got := fmt.Sprintf("%+v", chunks)
|
||||
|
||||
if got != expected {
|
||||
t.Errorf(
|
||||
"Failed test '%s':\nexpected: %s\ngot: %s",
|
||||
test.Name,
|
||||
expected,
|
||||
got,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue