From 372d236fe7079222d582d9be6167ac1e65cb3c87 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sun, 11 Sep 2016 22:46:11 -0400 Subject: [PATCH] fieldPath is now selectionReader --- ent/class.go | 2 - ent/entity.go | 20 ++++---- ent/fieldpath.go | 106 ----------------------------------------- ent/huff.go | 120 ++++++++++++++++++++++++----------------------- ent/selection.go | 82 ++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 176 deletions(-) delete mode 100644 ent/fieldpath.go create mode 100644 ent/selection.go diff --git a/ent/class.go b/ent/class.go index 50b2a98..8669f74 100644 --- a/ent/class.go +++ b/ent/class.go @@ -17,8 +17,6 @@ type Class struct { // maps field names back to their indexes. Entities use this to access // their own fields by name instead of by slot. fieldNames map[string]int - - fp *fieldPath } func (c *Class) New() *Entity { diff --git a/ent/entity.go b/ent/entity.go index 47dd8a6..84cc8af 100644 --- a/ent/entity.go +++ b/ent/entity.go @@ -16,17 +16,19 @@ func (e *Entity) Read(br bit.Reader) error { } Debug.Printf("entity %v read", e) - fp := newFieldPath() - if err := fp.read(br, htree, e.Class); err != nil { + r := newSelectionReader() + if err := r.read(br, htree); err != nil { return fmt.Errorf("unable to read entity: %v", err) } - for i := 0; i <= fp.hlast; i++ { - if fp.history[i][0] == 0 { - Debug.Printf("direct selection: %v", fp.history[i][1]) - Debug.Printf("field: %v", e.Class.Fields[fp.history[i][1]]) - } else { - Debug.Printf("child selection: %v (%v)", fp.history[i], - fp.history[i][1:fp.history[i][0]+2]) + + for _, s := range r.selections() { + switch s.count { + case 0: + Debug.Printf("FUCK!") + case 1: + Debug.Printf("direct selection: %v", s.path()) + default: + Debug.Printf("child selection: %v", s.path()) } } return nil diff --git a/ent/fieldpath.go b/ent/fieldpath.go deleted file mode 100644 index 57978d2..0000000 --- a/ent/fieldpath.go +++ /dev/null @@ -1,106 +0,0 @@ -package ent - -import ( - "fmt" - "github.com/jordanorelli/hyperstone/bit" -) - -type fieldPath struct { - // slice of values, to be reused over and over - vals [6]int - - // index of the last valid value. e.g., the head of the stack. - last int - - // history of fieldpath values. that is, all selections thus far. - // Everything is fixed width to avoid allocations as much as possible - // inside of the fieldpath stuff. history lengths are known to go over 500, - // but I honestly have no idea if there is or isn't a limit. this is a - // hazard. - history [1024][7]int - - // last valid index of a history entry - hlast int -} - -func newFieldPath() *fieldPath { - f := new(fieldPath) - f.vals[f.last] = -1 - f.hlast = -1 - return f -} - -func (f *fieldPath) add(i int) { - f.vals[f.last] += i -} - -func (f *fieldPath) push(i int) { - f.last++ - f.vals[f.last] = i -} - -func (f *fieldPath) pop() int { - f.last-- - return f.vals[f.last+1] -} - -func (f *fieldPath) replaceAll(fn func(v int) int) { - for i := 0; i <= f.last; i++ { - f.vals[i] = fn(f.vals[i]) - } -} - -// reads the sequence of id values off of the provided bit reader given the -// huffman tree of fieldpath ops rooted at the node n -func (f *fieldPath) read(br bit.Reader, n node, class *Class) error { - f.last = 0 - for fn := walk(n, br); fn != nil; fn = walk(n, br) { - if err := br.Err(); err != nil { - return fmt.Errorf("unable to read fieldpath: reader error: %v", err) - } - fn(f, br) - Debug.Printf("fieldpath: %v", f.path()) - f.keep() - } - return nil -} - -// adds our current vals to the history list. -// a history list entry is an array of ints, 7 ints wide. a fieldPath value is -// 6 ints wide. a history value encodes the number of valid entries in its -// first position. e.g., this: -// [0 0 0 0 0 0 0] -// would indicate the selection [0] -// [0 4 0 0 0 0 0] -// would indicate the selection [4] -// [1 4 2 0 0 0 0] -// would indicate the selection [4 2] -func (f *fieldPath) keep() { - f.hlast++ - f.history[f.hlast][0] = f.last - for i := 0; i <= f.last; i++ { - f.history[f.hlast][i+1] = f.vals[i] - } -} - -func (f *fieldPath) getField(class *Class) *Field { - if f.last > 0 { - for i := 0; i < f.last; i++ { - if f.vals[i] >= len(class.Fields) { - Info.Fatalf("bad access for field %d on class %v; class has only %d fields", f.vals[i], class, len(class.Fields)) - } - field := class.Fields[f.vals[i]] - if field.class == nil { - Info.Fatalf("class %s field at %d is %v, has no class", class, f.vals[i], field) - } else { - class = class.Fields[f.vals[i]].class - } - } - } - return class.Fields[f.vals[f.last]] -} - -// the subslice of valid index values that has been read on the fieldpath -func (f *fieldPath) path() []int { - return f.vals[:f.last+1] -} diff --git a/ent/huff.go b/ent/huff.go index d16c4fc..dc99513 100644 --- a/ent/huff.go +++ b/ent/huff.go @@ -33,7 +33,7 @@ type lNode struct { name string _rank int freq int - fn func(*fieldPath, bit.Reader) + fn selectionOp } func (n lNode) String() string { @@ -91,7 +91,9 @@ func makeTree(l nodeList) node { return l[0] } -func walk(n node, br bit.Reader) func(*fieldPath, bit.Reader) { +// walks the huffman tree rooted at the node n, returning the selection op +// encoded by the tree. +func walk(n node, br bit.Reader) selectionOp { switch v := n.(type) { case lNode: // Debug.Printf("fieldpath fn: %s", v.name) @@ -118,89 +120,89 @@ func dump(n node, prefix string, w io.Writer) { } var hlist = nodeList{ - lNode{"PlusOne", 0, 36271, func(fp *fieldPath, br bit.Reader) { - fp.add(1) + lNode{"PlusOne", 0, 36271, func(r *selectionReader, br bit.Reader) { + r.add(1) }}, lNode{"FieldPathEncodeFinish", 39, 25474, nil}, - lNode{"PushOneLeftDeltaNRightNonZeroPack6Bits", 11, 10530, func(fp *fieldPath, br bit.Reader) { + lNode{"PushOneLeftDeltaNRightNonZeroPack6Bits", 11, 10530, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushOneLeftDeltaNRightNonZeroPack6Bits") }}, - lNode{"PlusTwo", 1, 10334, func(fp *fieldPath, br bit.Reader) { - fp.add(2) + lNode{"PlusTwo", 1, 10334, func(r *selectionReader, br bit.Reader) { + r.add(2) }}, - lNode{"PlusN", 4, 4128, func(fp *fieldPath, br bit.Reader) { - fp.add(int(bit.ReadUBitVarFP(br)) + 5) + lNode{"PlusN", 4, 4128, func(r *selectionReader, br bit.Reader) { + r.add(int(bit.ReadUBitVarFP(br)) + 5) }}, - lNode{"PushOneLeftDeltaOneRightNonZero", 8, 2942, func(fp *fieldPath, br bit.Reader) { + lNode{"PushOneLeftDeltaOneRightNonZero", 8, 2942, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushOneLeftDeltaOneRightNonZero") }}, - lNode{"PopAllButOnePlusOne", 29, 1837, func(fp *fieldPath, br bit.Reader) { - fp.last = 0 - fp.add(1) + lNode{"PopAllButOnePlusOne", 29, 1837, func(r *selectionReader, br bit.Reader) { + r.cur.count = 1 + r.add(1) }}, - lNode{"PlusThree", 2, 1375, func(fp *fieldPath, br bit.Reader) { - fp.add(3) + lNode{"PlusThree", 2, 1375, func(r *selectionReader, br bit.Reader) { + r.add(3) }}, - lNode{"PlusFour", 3, 646, func(fp *fieldPath, br bit.Reader) { + lNode{"PlusFour", 3, 646, func(r *selectionReader, br bit.Reader) { panic("not implemented: PlusFour") }}, - lNode{"PopAllButOnePlusNPack6Bits", 32, 634, func(fp *fieldPath, br bit.Reader) { + lNode{"PopAllButOnePlusNPack6Bits", 32, 634, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopAllButOnePlusNPack6Bits") }}, - lNode{"PushOneLeftDeltaNRightZero", 9, 560, func(fp *fieldPath, br bit.Reader) { + lNode{"PushOneLeftDeltaNRightZero", 9, 560, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushOneLeftDeltaNRightZero") }}, - lNode{"PushOneLeftDeltaOneRightZero", 7, 521, func(fp *fieldPath, br bit.Reader) { - fp.add(1) - fp.push(0) + lNode{"PushOneLeftDeltaOneRightZero", 7, 521, func(r *selectionReader, br bit.Reader) { + r.add(1) + r.push(0) }}, - lNode{"PushOneLeftDeltaNRightNonZero", 10, 471, func(fp *fieldPath, br bit.Reader) { + lNode{"PushOneLeftDeltaNRightNonZero", 10, 471, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushOneLeftDeltaNRightNonZero") }}, - lNode{"PushNAndNonTopological", 26, 310, func(fp *fieldPath, br bit.Reader) { + lNode{"PushNAndNonTopological", 26, 310, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushNAndNonTopological") }}, - lNode{"PopAllButOnePlusNPack3Bits", 31, 300, func(fp *fieldPath, br bit.Reader) { + lNode{"PopAllButOnePlusNPack3Bits", 31, 300, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopAllButOnePlusNPack3Bits") }}, - lNode{"NonTopoPenultimatePlusOne", 37, 271, func(fp *fieldPath, br bit.Reader) { + lNode{"NonTopoPenultimatePlusOne", 37, 271, func(r *selectionReader, br bit.Reader) { panic("not implemented: NonTopoPenultimatePlusOne") }}, - lNode{"PushOneLeftDeltaNRightNonZeroPack8Bits", 12, 251, func(fp *fieldPath, br bit.Reader) { + lNode{"PushOneLeftDeltaNRightNonZeroPack8Bits", 12, 251, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushOneLeftDeltaNRightNonZeroPack8Bits") }}, - lNode{"PopAllButOnePlusN", 30, 149, func(fp *fieldPath, br bit.Reader) { + lNode{"PopAllButOnePlusN", 30, 149, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopAllButOnePlusN") }}, - lNode{"NonTopoComplexPack4Bits", 38, 99, func(fp *fieldPath, br bit.Reader) { - fp.replaceAll(func(i int) int { + lNode{"NonTopoComplexPack4Bits", 38, 99, func(r *selectionReader, br bit.Reader) { + r.måp(func(i int) int { if bit.ReadBool(br) { return i + int(br.ReadBits(4)) - 7 // ?! } return i }) }}, - lNode{"NonTopoComplex", 36, 76, func(fp *fieldPath, br bit.Reader) { - fp.replaceAll(func(i int) int { + lNode{"NonTopoComplex", 36, 76, func(r *selectionReader, br bit.Reader) { + r.måp(func(i int) int { if bit.ReadBool(br) { return i + int(bit.ReadZigZag32(br)) } return i }) }}, - lNode{"PushOneLeftDeltaZeroRightZero", 5, 35, func(fp *fieldPath, br bit.Reader) { - fp.push(0) + lNode{"PushOneLeftDeltaZeroRightZero", 5, 35, func(r *selectionReader, br bit.Reader) { + r.push(0) }}, - lNode{"PushOneLeftDeltaZeroRightNonZero", 6, 3, func(fp *fieldPath, br bit.Reader) { - fp.push(int(bit.ReadUBitVarFP(br))) + lNode{"PushOneLeftDeltaZeroRightNonZero", 6, 3, func(r *selectionReader, br bit.Reader) { + r.push(int(bit.ReadUBitVarFP(br))) }}, - lNode{"PopOnePlusOne", 27, 2, func(fp *fieldPath, br bit.Reader) { - fp.pop() - fp.add(1) + lNode{"PopOnePlusOne", 27, 2, func(r *selectionReader, br bit.Reader) { + r.pop() + r.add(1) }}, - lNode{"PopNAndNonTopographical", 35, 1, func(fp *fieldPath, br bit.Reader) { - fp.last -= int(bit.ReadUBitVarFP(br)) - fp.replaceAll(func(i int) int { + lNode{"PopNAndNonTopographical", 35, 1, func(r *selectionReader, br bit.Reader) { + r.count -= int(bit.ReadUBitVarFP(br)) + r.måp(func(i int) int { if bit.ReadBool(br) { return i + int(bit.ReadZigZag32(br)) } @@ -210,53 +212,53 @@ var hlist = nodeList{ // all the other operations have weights of 0 in clarity, which makes no // sense. - lNode{"PopNPlusN", 34, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PopNPlusN", 34, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopNPlusN") }}, - lNode{"PopNPlusOne", 33, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PopNPlusOne", 33, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopNPlusOne") }}, - lNode{"PopOnePlusN", 28, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PopOnePlusN", 28, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PopOnePlusN") }}, - lNode{"PushN", 25, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushN", 25, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushN") }}, - lNode{"PushThreePack5LeftDeltaN", 24, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreePack5LeftDeltaN", 24, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreePack5LeftDeltaN") }}, - lNode{"PushThreeLeftDeltaN", 23, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreeLeftDeltaN", 23, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreeLeftDeltaN") }}, - lNode{"PushTwoPack5LeftDeltaN", 22, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushTwoPack5LeftDeltaN", 22, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushTwoPack5LeftDeltaN") }}, - lNode{"PushTwoLeftDeltaN", 21, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushTwoLeftDeltaN", 21, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushTwoLeftDeltaN") }}, - lNode{"PushThreePack5LeftDeltaOne", 20, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreePack5LeftDeltaOne", 20, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreePack5LeftDeltaOne") }}, - lNode{"PushThreeLeftDeltaOne", 19, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreeLeftDeltaOne", 19, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreeLeftDeltaOne") }}, - lNode{"PushTwoPack5LeftDeltaOne", 18, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushTwoPack5LeftDeltaOne", 18, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushTwoPack5LeftDeltaOne") }}, - lNode{"PushTwoLeftDeltaOne", 17, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushTwoLeftDeltaOne", 17, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushTwoLeftDeltaOne") }}, - lNode{"PushThreePack5LeftDeltaZero", 16, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreePack5LeftDeltaZero", 16, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreePack5LeftDeltaZero") }}, - lNode{"PushThreeLeftDeltaZero", 15, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushThreeLeftDeltaZero", 15, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushThreeLeftDeltaZero") }}, - lNode{"PushTwoPack5LeftDeltaZero", 14, 1, func(fp *fieldPath, br bit.Reader) { - fp.push(int(br.ReadBits(5))) - fp.push(int(br.ReadBits(5))) + lNode{"PushTwoPack5LeftDeltaZero", 14, 1, func(r *selectionReader, br bit.Reader) { + r.push(int(br.ReadBits(5))) + r.push(int(br.ReadBits(5))) }}, - lNode{"PushTwoLeftDeltaZero", 13, 1, func(fp *fieldPath, br bit.Reader) { + lNode{"PushTwoLeftDeltaZero", 13, 1, func(r *selectionReader, br bit.Reader) { panic("not implemented: PushTwoLeftDeltaZero") }}, } diff --git a/ent/selection.go b/ent/selection.go new file mode 100644 index 0000000..6f63b37 --- /dev/null +++ b/ent/selection.go @@ -0,0 +1,82 @@ +package ent + +import ( + "fmt" + "github.com/jordanorelli/hyperstone/bit" +) + +type selectionOp func(*selectionReader, bit.Reader) + +// selection represents the selection of an individual entity slot. a count of +// 1 indicates that the selection is to be made directly on an entity. counts +// higher than 1 indiciate that the selection is to be made on either a member +// entity or an element of a member array. +type selection struct { + count int + vals [6]int +} + +func (s selection) path() []int { return s.vals[:s.count] } + +// selectionReader reads a set of field selections off of the wire. the +// selections are represented as arrays of slot positions to be traversed in +// order to select an entity slot. +type selectionReader struct { + // current selection; the selection being read off the wire right now + cur selection + + // the number of valid selections made thus far + count int + + // a list of past selections. values up to the index count-1 are considered + // valid. + all [1024]selection +} + +func newSelectionReader() *selectionReader { + r := new(selectionReader) + r.cur.count = 1 + r.cur.vals[0] = -1 + return r +} + +func (r *selectionReader) read(br bit.Reader, n node) error { + for fn := walk(n, br); fn != nil; fn = walk(n, br) { + if err := br.Err(); err != nil { + return fmt.Errorf("unable to read selection: bit reader error: %v", err) + } + fn(r, br) + Debug.Printf("selection: %v", r.cur.path()) + r.keep() + } + return nil +} + +func (r *selectionReader) selections() []selection { return r.all[:r.count] } + +// adds i to the current selection +func (r *selectionReader) add(i int) { + r.cur.vals[r.cur.count-1] += i +} + +// pushes the value i to the end of the current selection +func (r *selectionReader) push(i int) { + r.cur.vals[r.cur.count] = i + r.cur.count++ +} + +// pops the last value off of the current selection +func (r *selectionReader) pop() { r.cur.count-- } + +// maps a function over the current set of values in the current selection +func (r *selectionReader) måp(fn func(int) int) { + for i := 0; i < r.cur.count; i++ { + r.cur.vals[i] = fn(r.cur.vals[i]) + } +} + +// keep the current selection and move on to the next one +func (r *selectionReader) keep() { + r.all[r.count] = r.cur + r.count++ +}