Complete code of insert into span buffer. Looks complicated and needs testing.

This commit is contained in:
Sascha L. Teichmann 2014-10-21 12:08:01 +02:00
parent d880983abc
commit a82d20f14b

View File

@ -59,6 +59,7 @@ func (sp *SpanPool) FreeAll(s *Span) {
func (sp *SpanPool) Insert(s *Span, pos, value int32) *Span {
// No head -> create.
if s == nil {
s = sp.Alloc()
s.From = pos
@ -71,10 +72,10 @@ func (sp *SpanPool) Insert(s *Span, pos, value int32) *Span {
if pos < s.From {
// Same value and directly neighbored -> extend head.
if value == s.Value && pos == s.From-1 {
s.From--
s.From = pos
return s
}
// Disjunct -> create new.
// Disjunct -> create new head.
prev := sp.Alloc()
prev.From = pos
prev.To = pos
@ -83,7 +84,103 @@ func (sp *SpanPool) Insert(s *Span, pos, value int32) *Span {
return prev
}
// TODO: Implement the more complicated cases.
return nil
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
}
}
// Extend prev?
if prev.To == pos-1 && value == prev.Value {
prev.To = pos
return head
}
// New between prev and current.
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
if pos == s.To+1 && value == s.Value { // directly neighbored
s.To = pos
// Check if a gap has to be closed
next := s.Next
if next != nil {
if next.From == s.To-1 && value == next.Value {
s.To = next.To
s.Next = next.Next
sp.Free(next)
return head
}
// Extend next?
if pos == next.From-1 && value == next.Value {
next.From = pos
return head
}
// Before next -> New between current and next
if pos < next.From {
sn := sp.Alloc()
sn.From = pos
sn.To = pos
sn.Value = value
sn.Next = next
s.Next = sn
return head
}
} else { // No next -> new at tail
sn := sp.Alloc()
sn.From = pos
sn.To = pos
sn.Value = value
sn.Next = nil
s.Next = sn
return head
}
} else { // Not directly connected and/or values do not match.
next := s.Next
if next != nil {
if pos == next.From-1 && value == next.Value {
next.From = pos
return head
}
// Before next -> New between current and next
if pos < next.From {
sn := sp.Alloc()
sn.From = pos
sn.To = pos
sn.Value = value
sn.Next = next
s.Next = sn
return head
}
} else { // No next -> new at tail
sn := sp.Alloc()
sn.From = pos
sn.To = pos
sn.Value = value
sn.Next = nil
s.Next = sn
return head
}
}
default: // pos in span -> do not modify.
return head
}
prev = s
}
return head
}