vise/go/state/state.go

169 lines
3.3 KiB
Go
Raw Normal View History

2023-03-31 11:52:04 +02:00
package state
import (
2023-03-31 13:56:11 +02:00
"fmt"
2023-03-31 14:06:59 +02:00
"log"
2023-03-31 11:52:04 +02:00
)
type State struct {
Flags []byte
CacheSize uint32
CacheUseSize uint32
2023-03-31 11:59:55 +02:00
Cache []map[string]string
2023-03-31 14:24:14 +02:00
CacheMap map[string]string
2023-03-31 11:59:55 +02:00
ExecPath []string
2023-03-31 16:03:54 +02:00
Idx uint16
2023-03-31 11:52:04 +02:00
}
2023-03-31 14:06:59 +02:00
func NewState(bitSize uint64) State {
2023-03-31 11:52:04 +02:00
if bitSize == 0 {
panic("bitsize cannot be 0")
}
n := bitSize % 8
if n > 0 {
bitSize += (8 - n)
}
2023-03-31 16:24:29 +02:00
st := State{
2023-03-31 11:52:04 +02:00
Flags: make([]byte, bitSize / 8),
CacheSize: 0,
CacheUseSize: 0,
}
2023-03-31 16:24:29 +02:00
st.Down("")
return st
2023-03-31 11:52:04 +02:00
}
func(st State) WithCacheSize(cacheSize uint32) State {
st.CacheSize = cacheSize
return st
}
2023-03-31 11:59:55 +02:00
2023-03-31 16:03:54 +02:00
func(st *State) Down(input string) {
2023-03-31 11:59:55 +02:00
m := make(map[string]string)
st.Cache = append(st.Cache, m)
2023-03-31 14:24:14 +02:00
st.CacheMap = make(map[string]string)
2023-03-31 16:24:29 +02:00
st.ExecPath = append(st.ExecPath, input)
2023-03-31 11:59:55 +02:00
}
2023-03-31 16:03:54 +02:00
func(st *State) Add(key string, value string, sizeHint uint32) error {
2023-03-31 15:04:08 +02:00
checkFrame := st.frameOf(key)
if checkFrame > -1 {
return fmt.Errorf("key %v already defined in frame %v", key, checkFrame)
}
sz := st.checkCapacity(value)
2023-03-31 13:56:11 +02:00
if sz == 0 {
return fmt.Errorf("Cache capacity exceeded %v of %v", st.CacheUseSize + sz, st.CacheSize)
}
2023-03-31 15:04:08 +02:00
log.Printf("add key %s value size %v", key, sz)
st.Cache[len(st.Cache)-1][key] = value
2023-03-31 13:56:11 +02:00
st.CacheUseSize += sz
2023-03-31 16:03:54 +02:00
_ = sizeHint
return nil
}
func(st *State) Update(key string, value string) error {
checkFrame := st.frameOf(key)
if checkFrame == -1 {
return fmt.Errorf("key %v not defined", key)
}
r := st.Cache[checkFrame][key]
l := uint32(len(r))
st.Cache[checkFrame][key] = ""
if st.CacheMap[key] != "" {
st.CacheMap[key] = value
}
2023-03-31 16:03:54 +02:00
st.CacheUseSize -= l
sz := st.checkCapacity(value)
if sz == 0 {
baseUseSize := st.CacheUseSize
st.Cache[checkFrame][key] = r
st.CacheUseSize += l
return fmt.Errorf("Cache capacity exceeded %v of %v", baseUseSize + sz, st.CacheSize)
}
2023-03-31 11:59:55 +02:00
return nil
}
2023-03-31 14:24:14 +02:00
func(st *State) Map(k string) error {
m, err := st.Get()
if err != nil {
return err
}
st.CacheMap[k] = m[k]
return nil
}
2023-03-31 15:04:08 +02:00
func(st *State) Depth() uint8 {
return uint8(len(st.Cache))
}
2023-03-31 11:59:55 +02:00
func(st *State) Get() (map[string]string, error) {
2023-03-31 15:04:08 +02:00
if len(st.Cache) == 0 {
return nil, fmt.Errorf("get at top frame")
}
2023-03-31 11:59:55 +02:00
return st.Cache[len(st.Cache)-1], nil
}
2023-03-31 13:56:11 +02:00
func(st *State) Val(key string) (string, error) {
r := st.CacheMap[key]
if len(r) == 0 {
return "", fmt.Errorf("key %v not mapped", key)
}
return r, nil
}
2023-03-31 16:03:54 +02:00
func(st *State) Up() error {
2023-03-31 14:06:59 +02:00
l := len(st.Cache)
if l == 0 {
return fmt.Errorf("exit called beyond top frame")
}
l -= 1
m := st.Cache[l]
for k, v := range m {
sz := len(v)
st.CacheUseSize -= uint32(sz)
log.Printf("free frame %v key %v value size %v", l, k, sz)
}
st.Cache = st.Cache[:l]
2023-03-31 16:24:29 +02:00
st.ExecPath = st.ExecPath[:l]
2023-03-31 14:06:59 +02:00
return nil
2023-03-31 13:56:11 +02:00
}
2023-03-31 16:03:54 +02:00
func(st *State) Reset() {
if len(st.Cache) == 0 {
return
}
2023-03-31 15:04:08 +02:00
st.Cache = st.Cache[:1]
st.CacheUseSize = 0
2023-03-31 16:03:54 +02:00
return
2023-03-31 15:04:08 +02:00
}
func(st *State) Check(key string) bool {
return st.frameOf(key) == -1
}
2023-03-31 16:03:54 +02:00
// return 0-indexed frame number where key is defined. -1 if not defined
2023-03-31 15:04:08 +02:00
func(st *State) frameOf(key string) int {
log.Printf("--- %s", key)
for i, m := range st.Cache {
for k, _ := range m {
if k == key {
return i
}
}
}
return -1
}
2023-03-31 16:03:54 +02:00
// bytes that will be added to cache use size for string
// returns 0 if capacity would be exceeded
2023-03-31 13:56:11 +02:00
func(st *State) checkCapacity(v string) uint32 {
sz := uint32(len(v))
if st.CacheSize == 0 {
return sz
}
if st.CacheUseSize + sz > st.CacheSize {
return 0
}
return sz
}