Skip to content

Instantly share code, notes, and snippets.

@sbinet
Last active April 25, 2018 13:27
Show Gist options
  • Save sbinet/3730467f584d8a273285a2226e5d2d18 to your computer and use it in GitHub Desktop.
Save sbinet/3730467f584d8a273285a2226e5d2d18 to your computer and use it in GitHub Desktop.
simple tree of float64
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)
)

output

$> 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment