97 lines
1.5 KiB
Go
97 lines
1.5 KiB
Go
|
package rlepluslazy
|
||
|
|
||
|
func Sum(a, b RunIterator) (RunIterator, error) {
|
||
|
it := addIt{a: a, b: b}
|
||
|
it.prep()
|
||
|
return &it, nil
|
||
|
}
|
||
|
|
||
|
type addIt struct {
|
||
|
a RunIterator
|
||
|
b RunIterator
|
||
|
|
||
|
next Run
|
||
|
|
||
|
arun Run
|
||
|
brun Run
|
||
|
}
|
||
|
|
||
|
func (it *addIt) prep() error {
|
||
|
var err error
|
||
|
|
||
|
fetch := func() error {
|
||
|
if !it.arun.Valid() && it.a.HasNext() {
|
||
|
it.arun, err = it.a.NextRun()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !it.brun.Valid() && it.b.HasNext() {
|
||
|
it.brun, err = it.b.NextRun()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if err := fetch(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// one is not valid
|
||
|
if !it.arun.Valid() {
|
||
|
it.next = it.brun
|
||
|
it.brun.Len = 0
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if !it.brun.Valid() {
|
||
|
it.next = it.arun
|
||
|
it.arun.Len = 0
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if !it.arun.Val && !it.brun.Val {
|
||
|
min := it.arun.Len
|
||
|
if it.brun.Len < min {
|
||
|
min = it.brun.Len
|
||
|
}
|
||
|
it.next = Run{Val: it.arun.Val, Len: min}
|
||
|
it.arun.Len -= it.next.Len
|
||
|
it.brun.Len -= it.next.Len
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
it.next = Run{Val: true}
|
||
|
// different vals, 'true' wins
|
||
|
for (it.arun.Val && it.arun.Valid()) || (it.brun.Val && it.brun.Valid()) {
|
||
|
min := it.arun.Len
|
||
|
if it.brun.Len < min && it.brun.Valid() || !it.arun.Valid() {
|
||
|
min = it.brun.Len
|
||
|
}
|
||
|
it.next.Len += min
|
||
|
if it.arun.Valid() {
|
||
|
it.arun.Len -= min
|
||
|
}
|
||
|
if it.brun.Valid() {
|
||
|
it.brun.Len -= min
|
||
|
}
|
||
|
if err := fetch(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (it *addIt) HasNext() bool {
|
||
|
return it.next.Valid()
|
||
|
}
|
||
|
|
||
|
func (it *addIt) NextRun() (Run, error) {
|
||
|
next := it.next
|
||
|
return next, it.prep()
|
||
|
}
|