diff --git a/table.go b/table.go index 57286a6..ebf3caf 100644 --- a/table.go +++ b/table.go @@ -12,9 +12,16 @@ static int get_table_length(lua_State *L, int index) { */ import "C" 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 type TableValue 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))) } +// 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 func (s *State) PushTable(table map[string]interface{}) error { - s.NewTable() + s.CreateTable(0, len(table)) for k, v := range table { if err := s.PushValue(v); err != nil { return err } s.SetField(-2, k) } + // If this is a pooled table, return it + if _, hasEmptyKey := table[""]; len(table) == 1 && hasEmptyKey { + putTableToPool(table) + } return nil } // ToTable converts a Lua table to a Go map func (s *State) ToTable(index int) (map[string]interface{}, error) { absIdx := s.absIndex(index) - table := make(map[string]interface{}) + table := getTableFromPool() // Check if it's an array-like table length := s.GetTableLength(absIdx) @@ -59,7 +85,10 @@ func (s *State) ToTable(index int) (map[string]interface{}, error) { } 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 { key = s.ToString(-2) } 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) if err != nil { s.Pop(1) + putTableToPool(table) // Return table to pool on error return nil, err } @@ -108,3 +138,7 @@ func (s *State) SetTable(index int) { func (s *State) GetTable(index int) { 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)) +}