|
|
- // Copyright (c) 2017 Couchbase, Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package vellum
-
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "strconv"
- )
-
- func init() {
- registerDecoder(versionV1, func(data []byte) decoder {
- return newDecoderV1(data)
- })
- }
-
- type decoderV1 struct {
- data []byte
- }
-
- func newDecoderV1(data []byte) *decoderV1 {
- return &decoderV1{
- data: data,
- }
- }
-
- func (d *decoderV1) getRoot() int {
- if len(d.data) < footerSizeV1 {
- return noneAddr
- }
- footer := d.data[len(d.data)-footerSizeV1:]
- root := binary.LittleEndian.Uint64(footer[8:])
- return int(root)
- }
-
- func (d *decoderV1) getLen() int {
- if len(d.data) < footerSizeV1 {
- return 0
- }
- footer := d.data[len(d.data)-footerSizeV1:]
- dlen := binary.LittleEndian.Uint64(footer)
- return int(dlen)
- }
-
- func (d *decoderV1) stateAt(addr int, prealloc fstState) (fstState, error) {
- state, ok := prealloc.(*fstStateV1)
- if ok && state != nil {
- *state = fstStateV1{} // clear the struct
- } else {
- state = &fstStateV1{}
- }
- err := state.at(d.data, addr)
- if err != nil {
- return nil, err
- }
- return state, nil
- }
-
- type fstStateV1 struct {
- data []byte
- top int
- bottom int
- numTrans int
-
- // single trans only
- singleTransChar byte
- singleTransNext bool
- singleTransAddr uint64
- singleTransOut uint64
-
- // shared
- transSize int
- outSize int
-
- // multiple trans only
- final bool
- transTop int
- transBottom int
- destTop int
- destBottom int
- outTop int
- outBottom int
- outFinal int
- }
-
- func (f *fstStateV1) isEncodedSingle() bool {
- if f.data[f.top]>>7 > 0 {
- return true
- }
- return false
- }
-
- func (f *fstStateV1) at(data []byte, addr int) error {
- f.data = data
- if addr == emptyAddr {
- return f.atZero()
- } else if addr == noneAddr {
- return f.atNone()
- }
- if addr > len(data) || addr < 16 {
- return fmt.Errorf("invalid address %d/%d", addr, len(data))
- }
- f.top = addr
- f.bottom = addr
- if f.isEncodedSingle() {
- return f.atSingle(data, addr)
- }
- return f.atMulti(data, addr)
- }
-
- func (f *fstStateV1) atZero() error {
- f.top = 0
- f.bottom = 1
- f.numTrans = 0
- f.final = true
- f.outFinal = 0
- return nil
- }
-
- func (f *fstStateV1) atNone() error {
- f.top = 0
- f.bottom = 1
- f.numTrans = 0
- f.final = false
- f.outFinal = 0
- return nil
- }
-
- func (f *fstStateV1) atSingle(data []byte, addr int) error {
- // handle single transition case
- f.numTrans = 1
- f.singleTransNext = data[f.top]&transitionNext > 0
- f.singleTransChar = data[f.top] & maxCommon
- if f.singleTransChar == 0 {
- f.bottom-- // extra byte for uncommon
- f.singleTransChar = data[f.bottom]
- } else {
- f.singleTransChar = decodeCommon(f.singleTransChar)
- }
- if f.singleTransNext {
- // now we know the bottom, can compute next addr
- f.singleTransAddr = uint64(f.bottom - 1)
- f.singleTransOut = 0
- } else {
- f.bottom-- // extra byte with pack sizes
- f.transSize, f.outSize = decodePackSize(data[f.bottom])
- f.bottom -= f.transSize // exactly one trans
- f.singleTransAddr = readPackedUint(data[f.bottom : f.bottom+f.transSize])
- if f.outSize > 0 {
- f.bottom -= f.outSize // exactly one out (could be length 0 though)
- f.singleTransOut = readPackedUint(data[f.bottom : f.bottom+f.outSize])
- } else {
- f.singleTransOut = 0
- }
- // need to wait till we know bottom
- if f.singleTransAddr != 0 {
- f.singleTransAddr = uint64(f.bottom) - f.singleTransAddr
- }
- }
- return nil
- }
-
- func (f *fstStateV1) atMulti(data []byte, addr int) error {
- // handle multiple transitions case
- f.final = data[f.top]&stateFinal > 0
- f.numTrans = int(data[f.top] & maxNumTrans)
- if f.numTrans == 0 {
- f.bottom-- // extra byte for number of trans
- f.numTrans = int(data[f.bottom])
- if f.numTrans == 1 {
- // can't really be 1 here, this is special case that means 256
- f.numTrans = 256
- }
- }
- f.bottom-- // extra byte with pack sizes
- f.transSize, f.outSize = decodePackSize(data[f.bottom])
-
- f.transTop = f.bottom
- f.bottom -= f.numTrans // one byte for each transition
- f.transBottom = f.bottom
-
- f.destTop = f.bottom
- f.bottom -= f.numTrans * f.transSize
- f.destBottom = f.bottom
-
- if f.outSize > 0 {
- f.outTop = f.bottom
- f.bottom -= f.numTrans * f.outSize
- f.outBottom = f.bottom
- if f.final {
- f.bottom -= f.outSize
- f.outFinal = f.bottom
- }
- }
- return nil
- }
-
- func (f *fstStateV1) Address() int {
- return f.top
- }
-
- func (f *fstStateV1) Final() bool {
- return f.final
- }
-
- func (f *fstStateV1) FinalOutput() uint64 {
- if f.final && f.outSize > 0 {
- return readPackedUint(f.data[f.outFinal : f.outFinal+f.outSize])
- }
- return 0
- }
-
- func (f *fstStateV1) NumTransitions() int {
- return f.numTrans
- }
-
- func (f *fstStateV1) TransitionAt(i int) byte {
- if f.isEncodedSingle() {
- return f.singleTransChar
- }
- transitionKeys := f.data[f.transBottom:f.transTop]
- return transitionKeys[f.numTrans-i-1]
- }
-
- func (f *fstStateV1) TransitionFor(b byte) (int, int, uint64) {
- if f.isEncodedSingle() {
- if f.singleTransChar == b {
- return 0, int(f.singleTransAddr), f.singleTransOut
- }
- return -1, noneAddr, 0
- }
- transitionKeys := f.data[f.transBottom:f.transTop]
- pos := bytes.IndexByte(transitionKeys, b)
- if pos < 0 {
- return -1, noneAddr, 0
- }
- transDests := f.data[f.destBottom:f.destTop]
- dest := int(readPackedUint(transDests[pos*f.transSize : pos*f.transSize+f.transSize]))
- if dest > 0 {
- // convert delta
- dest = f.bottom - dest
- }
- transVals := f.data[f.outBottom:f.outTop]
- var out uint64
- if f.outSize > 0 {
- out = readPackedUint(transVals[pos*f.outSize : pos*f.outSize+f.outSize])
- }
- return f.numTrans - pos - 1, dest, out
- }
-
- func (f *fstStateV1) String() string {
- rv := ""
- rv += fmt.Sprintf("State: %d (%#x)", f.top, f.top)
- if f.final {
- rv += " final"
- fout := f.FinalOutput()
- if fout != 0 {
- rv += fmt.Sprintf(" (%d)", fout)
- }
- }
- rv += "\n"
- rv += fmt.Sprintf("Data: % x\n", f.data[f.bottom:f.top+1])
-
- for i := 0; i < f.numTrans; i++ {
- transChar := f.TransitionAt(i)
- _, transDest, transOut := f.TransitionFor(transChar)
- rv += fmt.Sprintf(" - %d (%#x) '%s' ---> %d (%#x) with output: %d", transChar, transChar, string(transChar), transDest, transDest, transOut)
- rv += "\n"
- }
- if f.numTrans == 0 {
- rv += "\n"
- }
- return rv
- }
-
- func (f *fstStateV1) DotString(num int) string {
- rv := ""
- label := fmt.Sprintf("%d", num)
- final := ""
- if f.final {
- final = ",peripheries=2"
- }
- rv += fmt.Sprintf(" %d [label=\"%s\"%s];\n", f.top, label, final)
-
- for i := 0; i < f.numTrans; i++ {
- transChar := f.TransitionAt(i)
- _, transDest, transOut := f.TransitionFor(transChar)
- out := ""
- if transOut != 0 {
- out = fmt.Sprintf("/%d", transOut)
- }
- rv += fmt.Sprintf(" %d -> %d [label=\"%s%s\"];\n", f.top, transDest, escapeInput(transChar), out)
- }
-
- return rv
- }
-
- func escapeInput(b byte) string {
- x := strconv.AppendQuoteRune(nil, rune(b))
- return string(x[1:(len(x) - 1)])
- }
|