diff --git a/common/spans.go b/common/spans.go index d777fcf..00b1738 100644 --- a/common/spans.go +++ b/common/spans.go @@ -90,65 +90,33 @@ func (sp *SpanPool) Insert(s *Span, pos, value int32) *Span { } head := s - for prev := s; s != nil; s = s.Next { - switch { - case pos < s.From: // before span - if pos == s.From-1 && value == s.Value { // directly neighbored - s.From = pos - // Check if a gap has to be closed. - if prev.To == s.From-1 && value == prev.Value { - prev.To = s.To - prev.Next = s.Next - sp.Free(s) - return head - } + for ; s != nil && pos > s.To; s = s.Next { + next := s.Next + if pos == s.To+1 && value == s.Value { // directly neighbored + s.To = pos + // Check if a gap has to be closed + if next != nil && next.From == s.To+1 && value == next.Value { + s.To = next.To + s.Next = next.Next + sp.Free(next) } - // Extend prev? - if prev.To == pos-1 && value == prev.Value { - prev.To = pos - return head - } - // New between prev and current. + return head + } + // Extend next? + if next != nil && pos == next.From-1 && value == next.Value { + next.From = pos + return head + } + // Before next -> New between current and next + if next == nil || pos < next.From { sn := sp.Alloc() sn.From = pos sn.To = pos sn.Value = value - sn.Next = s - prev.Next = sn - return head - - case pos > s.To: // after span - next := s.Next - if pos == s.To+1 && value == s.Value { // directly neighbored - s.To = pos - // Check if a gap has to be closed - if next != nil && next.From == s.To+1 && value == next.Value { - s.To = next.To - s.Next = next.Next - sp.Free(next) - } - return head - } - // Extend next? - if next != nil && pos == next.From-1 && value == next.Value { - next.From = pos - return head - } - // Before next -> New between current and next - if next == nil || pos < next.From { - sn := sp.Alloc() - sn.From = pos - sn.To = pos - sn.Value = value - sn.Next = next - s.Next = sn - return head - } - - default: // pos in span -> do not modify. + sn.Next = next + s.Next = sn return head } - prev = s } return head diff --git a/common/spans_test.go b/common/spans_test.go index 0144ccf..ffd8061 100644 --- a/common/spans_test.go +++ b/common/spans_test.go @@ -9,26 +9,68 @@ import ( "testing" ) -func TestSpans(t *testing.T) { +const spanItems = 3000 - inp := make([]int32, 3000) - for i, n := 0, len(inp); i < n; i++ { - inp[i] = int32(i) - } - for i, n := 0, len(inp); i < n; i++ { - i1 := rand.Int31n(int32(n)) - i2 := rand.Int31n(int32(n)) - inp[i1], inp[i2] = inp[i2], inp[i1] - } +func TestSpans(t *testing.T) { sp := NewSpanPool() var s *Span - for i, n := 0, len(inp); i < n; i++ { + + for i := 0; i < spanItems; i++ { + s = sp.Insert(s, int32(i), 42) + } + + if n := s.Len(); n != 1 { + t.Errorf("inc: Span length %d expected 1\n", n) + t.Errorf("spans: %s\n", s) + } + + sp.FreeAll(s) + + s = nil + for i := spanItems - 1; i >= 0; i-- { + s = sp.Insert(s, int32(i), 42) + } + + if n := s.Len(); n != 1 { + t.Errorf("dec: Span length %d expected 1\n", n) + t.Errorf("spans: %s\n", s) + } + + sp.FreeAll(s) + + s = nil + for i := 0; i < spanItems/2; i++ { + j := spanItems - 1 - i + s = sp.Insert(s, int32(i), 42) + s = sp.Insert(s, int32(j), 21) + } + + if n := s.Len(); n != 2 { + t.Errorf("two: Span length %d expected 2\n", n) + t.Errorf("spans: %s\n", s) + } + + sp.FreeAll(s) + + inp := make([]int32, spanItems) + for i := 0; i < spanItems; i++ { + inp[i] = int32(i) + } + + for i := 0; i < spanItems; i++ { + i1 := rand.Int31n(int32(spanItems)) + i2 := rand.Int31n(int32(spanItems)) + inp[i1], inp[i2] = inp[i2], inp[i1] + } + + s = nil + for i := 0; i < spanItems; i++ { s = sp.Insert(s, inp[i], 42) } if n := s.Len(); n != 1 { - t.Errorf("Span length %d expected 1\n", n) + t.Errorf("rand: Span length %d expected 1\n", n) t.Errorf("spans: %s\n", s) }