$> go run chain.go
=== test tree ===
entries: 10
entry[0]: 1
entry[1]: 2
entry[2]: 3
entry[3]: 4
entry[4]: 5
entry[5]: 6
entry[6]: 7
entry[7]: 8
entry[8]: 9
entry[9]: 10
=== test tree ===
entries: 20
entry[0]: 1
entry[1]: 2
entry[2]: 3
entry[3]: 4
entry[4]: 5
entry[5]: 6
entry[6]: 7
entry[7]: 8
entry[8]: 9
entry[9]: 10
entry[10]: 11
entry[11]: 12
entry[12]: 13
entry[13]: 14
entry[14]: 15
entry[15]: 16
entry[16]: 17
entry[17]: 18
entry[18]: 19
entry[19]: 20
Last active
April 25, 2018 13:27
-
-
Save sbinet/3730467f584d8a273285a2226e5d2d18 to your computer and use it in GitHub Desktop.
simple tree of float64
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
) | |
func main() { | |
log.SetFlags(0) | |
log.SetPrefix("") | |
t1 := &ttree{data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}} | |
t2 := &ttree{data: []float64{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}} | |
testTree(t1) | |
testTree(Chain(t1, t2)) | |
} | |
func testTree(tree Tree) { | |
log.Printf("=== test tree ===") | |
log.Printf("entries: %v", tree.Entries()) | |
sc := NewScanner(tree) | |
defer sc.Close() | |
for sc.Next() { | |
var v float64 | |
err := sc.Scan(&v) | |
if err != nil { | |
log.Fatalf("entry[%d]: could not load data: %v", sc.Entry(), err) | |
} | |
log.Printf("entry[%d]: %v", sc.Entry(), v) | |
} | |
err := sc.Close() | |
if err != nil { | |
log.Fatalf("could not close scanner: %v", err) | |
} | |
} | |
type Tree interface { | |
Entries() int | |
Data() float64 | |
Load(i int) error | |
} | |
type scanner struct { | |
tree Tree | |
i int // number of entries iterated over | |
n int // number of entries to iterate over | |
cur int // current entry index | |
closed bool | |
} | |
func NewScanner(t Tree) *scanner { | |
return &scanner{ | |
tree: t, | |
i: 0, | |
n: t.Entries(), | |
cur: -1, | |
} | |
} | |
func (s *scanner) Close() error { | |
if s.closed { | |
return nil | |
} | |
s.closed = true | |
return nil | |
} | |
func (s *scanner) Entry() int { | |
return s.cur | |
} | |
func (s *scanner) Next() bool { | |
if s.closed { | |
return false | |
} | |
next := s.i < s.n | |
s.cur++ | |
s.i++ | |
return next | |
} | |
func (s *scanner) Scan(v *float64) error { | |
err := s.tree.Load(s.cur) | |
if err != nil { | |
return err | |
} | |
*v = s.tree.Data() | |
return nil | |
} | |
type ttree struct { | |
data []float64 | |
entry int | |
} | |
func (t ttree) Entries() int { | |
return len(t.data) | |
} | |
func (t ttree) Data() float64 { | |
return t.data[t.entry] | |
} | |
func (t *ttree) Load(i int) error { | |
if i >= len(t.data) { | |
return fmt.Errorf("out of bound") | |
} | |
t.entry = i | |
return nil | |
} | |
func Chain(trees ...Tree) Tree { | |
ch := &tchain{ | |
trees: make([]itree, len(trees)), | |
cur: -1, | |
} | |
sum := 0 | |
offset := 0 | |
for i := range trees { | |
t := trees[i] | |
n := t.Entries() | |
sum += n | |
ch.trees[i] = itree{tree: t, offset: offset, total: sum} | |
offset += n | |
} | |
if len(trees) > 0 { | |
ch.cur = 0 | |
ch.tree = &ch.trees[ch.cur] | |
} | |
return ch | |
} | |
type tchain struct { | |
trees []itree | |
cur int | |
tree *itree | |
} | |
type itree struct { | |
tree Tree | |
offset int | |
total int | |
} | |
func (t itree) Entries() int { | |
return t.tree.Entries() | |
} | |
func (t itree) Data() float64 { | |
return t.tree.Data() | |
} | |
func (t *itree) Load(i int) error { | |
j := i - t.offset | |
return t.tree.Load(j) | |
} | |
func (ch tchain) Entries() int { | |
if len(ch.trees) <= 0 { | |
return 0 | |
} | |
return ch.trees[len(ch.trees)-1].total | |
} | |
func (ch tchain) Data() float64 { | |
if ch.tree == nil { | |
return 0 | |
} | |
return ch.tree.Data() | |
} | |
func (ch *tchain) Load(i int) error { | |
if ch.tree == nil { | |
return fmt.Errorf("invalid chain") | |
} | |
if i >= ch.tree.total { | |
ch.cur++ | |
ch.tree = &ch.trees[ch.cur] | |
} | |
return ch.tree.Load(i) | |
} | |
var ( | |
_ Tree = (*ttree)(nil) | |
_ Tree = (*tchain)(nil) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment