crushkv/crushmap/text_bucket.go
Vasiliy Tolstov 24f641df0d initial rewrite
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2019-04-18 23:13:04 +03:00

338 lines
5.1 KiB
Go

package crushmap
import (
"errors"
"fmt"
"strconv"
)
func bucketState(l *lex) stateFn {
l.lexEmit(itemBucketBeg)
return bucketStartState
}
func bucketStartState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
r := l.lexPeek()
switch r {
case '{':
l.lexNext()
l.lexIgnore()
return bucketIdentState
case '#':
l.lexErr(fmt.Sprintf("unexpected token %q", r))
return l.lexPop()
}
return bucketNameState
}
func bucketNameState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop:
for {
r := l.lexPeek()
switch r {
case '{':
l.lexNext()
l.lexIgnore()
break loop
case ' ':
break loop
case '\n', '#':
l.lexErr(fmt.Sprintf("unexpected token %q", r))
return l.lexPop()
default:
l.lexNext()
}
}
l.lexEmit(itemBucketName)
return bucketIdentState
}
func bucketIDState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop1:
for {
r := l.lexPeek()
switch r {
case ' ', '\n', '#', '\t':
break loop1
}
l.lexNext()
}
l.lexEmit(itemBucketID)
l.lexTake(" \t")
l.lexIgnore()
loop2:
for {
r := l.lexPeek()
switch r {
case ' ', '\n', '#', '\t':
break loop2
default:
l.lexNext()
}
}
switch l.lexCurrent() {
case "class":
l.lexIgnore()
return bucketIDClassState
}
return bucketIdentState
}
func bucketIDClassState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop:
for {
r := l.lexPeek()
switch r {
case ' ', '\n', '#', '\t':
break loop
default:
l.lexNext()
}
}
l.lexEmit(itemBucketIDClass)
return bucketIdentState
}
func bucketHashState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
l.lexTake("0123456789")
l.lexEmit(itemBucketHash)
return bucketIdentState
}
func bucketAlgState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
for {
r := l.lexPeek()
if r == '\n' || r == ' ' || r == '#' {
break
}
l.lexNext()
}
l.lexEmit(itemBucketAlg)
return bucketIdentState
}
func bucketItemState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop:
for {
r := l.lexPeek()
switch r {
case ' ':
break loop
case '\n', '#':
l.lexErr(fmt.Sprintf("unexpected token %q", r))
return l.lexPop()
}
l.lexNext()
}
l.lexEmit(itemBucketItemName)
return bucketItemIdentState
}
func bucketItemIdentState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop:
for {
r := l.lexPeek()
switch r {
case ' ', '\n':
break loop
case '#':
break loop
default:
l.lexNext()
}
}
switch l.lexCurrent() {
case "weight":
l.lexIgnore()
return bucketItemWeightState
case "pos":
l.lexIgnore()
return bucketItemPosState
}
l.lexEmit(itemBucketItemEnd)
return bucketIdentState
}
func bucketItemWeightState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
l.lexTake(".0123456789")
l.lexEmit(itemBucketItemWeight)
return bucketItemIdentState
}
func bucketItemPosState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
l.lexTake("0123456789")
l.lexEmit(itemBucketItemPos)
return bucketItemIdentState
}
func bucketIdentState(l *lex) stateFn {
l.lexTake(" \t")
l.lexIgnore()
loop:
for {
r := l.lexPeek()
switch r {
case ' ':
break loop
case '#':
l.lexNext()
l.lexIgnore()
l.lexPush(bucketIdentState)
return commentLineState
case '}':
l.lexNext()
l.lexIgnore()
l.lexEmit(itemBucketEnd)
return l.lexPop()
case '\n':
l.lexNext()
l.lexIgnore()
return bucketIdentState
default:
l.lexNext()
}
}
switch l.lexCurrent() {
case "id":
l.lexIgnore()
return bucketIDState
case "alg":
l.lexIgnore()
return bucketAlgState
case "hash":
l.lexIgnore()
return bucketHashState
case "item":
l.lexIgnore()
l.lexEmit(itemBucketItemBeg)
return bucketItemState
}
return l.lexPop()
}
func (p *textParser) handleBucket(itype string) (*Bucket, error) {
ibucket := &Bucket{TypeName: itype}
Loop:
for {
tok, done := p.l.lexNextToken()
if done {
break Loop
}
switch tok.itype {
case itemEOF, itemBucketEnd:
break Loop
case itemComment:
continue
case itemBucketName:
ibucket.Name = tok.ivalue
case itemBucketIDClass:
ibucket.IDClass = tok.ivalue
case itemBucketID:
id, err := strconv.Atoi(tok.ivalue)
if err != nil {
return nil, err
}
ibucket.ID = int32(id)
case itemBucketAlg:
ibucket.Alg = tok.ivalue
case itemBucketHash:
if tok.ivalue == "0" {
ibucket.Hash = "rjenkins1"
} else {
return nil, errors.New("invalid bucket hash")
}
case itemBucketItemBeg:
item, err := p.handleBucketItem()
if err != nil {
return nil, err
}
ibucket.Items = append(ibucket.Items, item)
}
}
return ibucket, nil
}
func (p *textParser) handleBucketItem() (*Item, error) {
item := &Item{}
Loop:
for {
tok, done := p.l.lexNextToken()
if done {
break Loop
}
switch tok.itype {
case itemEOF, itemBucketItemEnd:
break Loop
case itemComment:
continue
case itemBucketItemName:
item.Name = tok.ivalue
case itemBucketItemWeight:
id, err := strconv.ParseFloat(tok.ivalue, 32)
if err != nil {
return nil, err
}
item.Weight = float32(id)
case itemBucketItemPos:
id, err := strconv.Atoi(tok.ivalue)
if err != nil {
return nil, err
}
item.Pos = id
}
}
return item, nil
}