added table pooling and some micro-ops

This commit is contained in:
Sky Johnson 2025-02-13 07:11:13 -06:00
parent 4dc266201f
commit 865ac8859f

View File

@ -12,9 +12,16 @@ static int get_table_length(lua_State *L, int index) {
*/ */
import "C" import "C"
import ( import (
"fmt" "strconv"
"sync"
) )
var tablePool = sync.Pool{
New: func() interface{} {
return make(map[string]interface{})
},
}
// TableValue represents any value that can be stored in a Lua table // TableValue represents any value that can be stored in a Lua table
type TableValue interface { type TableValue interface {
~string | ~float64 | ~bool | ~int | ~map[string]interface{} | ~[]float64 | ~[]interface{} ~string | ~float64 | ~bool | ~int | ~map[string]interface{} | ~[]float64 | ~[]interface{}
@ -22,22 +29,41 @@ type TableValue interface {
func (s *State) GetTableLength(index int) int { return int(C.get_table_length(s.L, C.int(index))) } func (s *State) GetTableLength(index int) int { return int(C.get_table_length(s.L, C.int(index))) }
// getTableFromPool gets a map from the pool and ensures it's empty
func getTableFromPool() map[string]interface{} {
table := tablePool.Get().(map[string]interface{})
// Clear any existing entries
for k := range table {
delete(table, k)
}
return table
}
// putTableToPool returns a map to the pool
func putTableToPool(table map[string]interface{}) {
tablePool.Put(table)
}
// PushTable pushes a Go map onto the Lua stack as a table // PushTable pushes a Go map onto the Lua stack as a table
func (s *State) PushTable(table map[string]interface{}) error { func (s *State) PushTable(table map[string]interface{}) error {
s.NewTable() s.CreateTable(0, len(table))
for k, v := range table { for k, v := range table {
if err := s.PushValue(v); err != nil { if err := s.PushValue(v); err != nil {
return err return err
} }
s.SetField(-2, k) s.SetField(-2, k)
} }
// If this is a pooled table, return it
if _, hasEmptyKey := table[""]; len(table) == 1 && hasEmptyKey {
putTableToPool(table)
}
return nil return nil
} }
// ToTable converts a Lua table to a Go map // ToTable converts a Lua table to a Go map
func (s *State) ToTable(index int) (map[string]interface{}, error) { func (s *State) ToTable(index int) (map[string]interface{}, error) {
absIdx := s.absIndex(index) absIdx := s.absIndex(index)
table := make(map[string]interface{}) table := getTableFromPool()
// Check if it's an array-like table // Check if it's an array-like table
length := s.GetTableLength(absIdx) length := s.GetTableLength(absIdx)
@ -59,7 +85,10 @@ func (s *State) ToTable(index int) (map[string]interface{}, error) {
} }
if isArray { if isArray {
return map[string]interface{}{"": array}, nil putTableToPool(table) // Return unused table to pool
result := getTableFromPool()
result[""] = array
return result, nil
} }
} }
@ -71,12 +100,13 @@ func (s *State) ToTable(index int) (map[string]interface{}, error) {
if valueType == C.LUA_TSTRING { if valueType == C.LUA_TSTRING {
key = s.ToString(-2) key = s.ToString(-2)
} else if valueType == C.LUA_TNUMBER { } else if valueType == C.LUA_TNUMBER {
key = fmt.Sprintf("%g", s.ToNumber(-2)) key = strconv.FormatFloat(s.ToNumber(-2), 'g', -1, 64)
} }
value, err := s.ToValue(-1) value, err := s.ToValue(-1)
if err != nil { if err != nil {
s.Pop(1) s.Pop(1)
putTableToPool(table) // Return table to pool on error
return nil, err return nil, err
} }
@ -108,3 +138,7 @@ func (s *State) SetTable(index int) {
func (s *State) GetTable(index int) { func (s *State) GetTable(index int) {
C.lua_gettable(s.L, C.int(index)) C.lua_gettable(s.L, C.int(index))
} }
func (s *State) CreateTable(narr, nrec int) {
C.lua_createtable(s.L, C.int(narr), C.int(nrec))
}