introduce batching
This commit is contained in:
parent
0e12e19567
commit
cbfc8c184e
447
batch.go
Normal file
447
batch.go
Normal file
@ -0,0 +1,447 @@
|
||||
package luajit
|
||||
|
||||
/*
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Batch table field setting - single C call for multiple fields
|
||||
int batch_set_string_fields(lua_State *L, int table_idx,
|
||||
char **keys, char **values, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushstring(L, values[i]);
|
||||
lua_setfield(L, table_idx, keys[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_set_number_fields(lua_State *L, int table_idx,
|
||||
char **keys, double *values, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, values[i]);
|
||||
lua_setfield(L, table_idx, keys[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_set_bool_fields(lua_State *L, int table_idx,
|
||||
char **keys, int *values, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushboolean(L, values[i]);
|
||||
lua_setfield(L, table_idx, keys[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Batch array creation - build entire array in C
|
||||
int batch_push_int_array(lua_State *L, int *values, int count) {
|
||||
lua_createtable(L, count, 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, i + 1);
|
||||
lua_pushnumber(L, values[i]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_push_float_array(lua_State *L, double *values, int count) {
|
||||
lua_createtable(L, count, 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, i + 1);
|
||||
lua_pushnumber(L, values[i]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_push_string_array(lua_State *L, char **values, int count) {
|
||||
lua_createtable(L, count, 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, i + 1);
|
||||
lua_pushstring(L, values[i]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_push_bool_array(lua_State *L, int *values, int count) {
|
||||
lua_createtable(L, count, 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, i + 1);
|
||||
lua_pushboolean(L, values[i]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Batch array extraction - extract entire array in C
|
||||
int batch_extract_int_array(lua_State *L, int table_idx, int *buffer, int length) {
|
||||
for (int i = 1; i <= length; i++) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, table_idx);
|
||||
buffer[i-1] = (int)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_extract_float_array(lua_State *L, int table_idx, double *buffer, int length) {
|
||||
for (int i = 1; i <= length; i++) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, table_idx);
|
||||
buffer[i-1] = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_extract_string_array(lua_State *L, int table_idx, char **buffer, int length) {
|
||||
for (int i = 1; i <= length; i++) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, table_idx);
|
||||
size_t len;
|
||||
const char *str = lua_tolstring(L, -1, &len);
|
||||
if (str) {
|
||||
buffer[i-1] = malloc(len + 1);
|
||||
memcpy(buffer[i-1], str, len);
|
||||
buffer[i-1][len] = '\0';
|
||||
} else {
|
||||
buffer[i-1] = malloc(1);
|
||||
buffer[i-1][0] = '\0';
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batch_extract_bool_array(lua_State *L, int table_idx, int *buffer, int length) {
|
||||
for (int i = 1; i <= length; i++) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, table_idx);
|
||||
buffer[i-1] = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BatchSetStringFields sets multiple string fields on a table in one C call
|
||||
func (s *State) BatchSetStringFields(tableIndex int, fields map[string]string) error {
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := make([]*C.char, len(fields))
|
||||
values := make([]*C.char, len(fields))
|
||||
|
||||
i := 0
|
||||
for k, v := range fields {
|
||||
keys[i] = C.CString(k)
|
||||
values[i] = C.CString(v)
|
||||
i++
|
||||
}
|
||||
|
||||
C.batch_set_string_fields(s.L, C.int(tableIndex), &keys[0], &values[0], C.int(len(fields)))
|
||||
|
||||
for j := range len(fields) {
|
||||
C.free(unsafe.Pointer(keys[j]))
|
||||
C.free(unsafe.Pointer(values[j]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchSetNumberFields sets multiple number fields on a table in one C call
|
||||
func (s *State) BatchSetNumberFields(tableIndex int, fields map[string]float64) error {
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := make([]*C.char, len(fields))
|
||||
values := make([]C.double, len(fields))
|
||||
|
||||
i := 0
|
||||
for k, v := range fields {
|
||||
keys[i] = C.CString(k)
|
||||
values[i] = C.double(v)
|
||||
i++
|
||||
}
|
||||
|
||||
C.batch_set_number_fields(s.L, C.int(tableIndex), &keys[0], &values[0], C.int(len(fields)))
|
||||
|
||||
for j := range len(fields) {
|
||||
C.free(unsafe.Pointer(keys[j]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchSetBoolFields sets multiple boolean fields on a table in one C call
|
||||
func (s *State) BatchSetBoolFields(tableIndex int, fields map[string]bool) error {
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := make([]*C.char, len(fields))
|
||||
values := make([]C.int, len(fields))
|
||||
|
||||
i := 0
|
||||
for k, v := range fields {
|
||||
keys[i] = C.CString(k)
|
||||
if v {
|
||||
values[i] = 1
|
||||
} else {
|
||||
values[i] = 0
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
C.batch_set_bool_fields(s.L, C.int(tableIndex), &keys[0], &values[0], C.int(len(fields)))
|
||||
|
||||
for j := range len(fields) {
|
||||
C.free(unsafe.Pointer(keys[j]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchPushIntArray creates and pushes an int array in a single C call
|
||||
func (s *State) BatchPushIntArray(values []int) error {
|
||||
if len(values) == 0 {
|
||||
s.CreateTable(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
cValues := make([]C.int, len(values))
|
||||
for i, v := range values {
|
||||
cValues[i] = C.int(v)
|
||||
}
|
||||
|
||||
C.batch_push_int_array(s.L, &cValues[0], C.int(len(values)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchPushFloatArray creates and pushes a float array in a single C call
|
||||
func (s *State) BatchPushFloatArray(values []float64) error {
|
||||
if len(values) == 0 {
|
||||
s.CreateTable(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
cValues := make([]C.double, len(values))
|
||||
for i, v := range values {
|
||||
cValues[i] = C.double(v)
|
||||
}
|
||||
|
||||
C.batch_push_float_array(s.L, &cValues[0], C.int(len(values)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchPushStringArray creates and pushes a string array in a single C call
|
||||
func (s *State) BatchPushStringArray(values []string) error {
|
||||
if len(values) == 0 {
|
||||
s.CreateTable(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
cValues := make([]*C.char, len(values))
|
||||
for i, v := range values {
|
||||
cValues[i] = C.CString(v)
|
||||
}
|
||||
|
||||
C.batch_push_string_array(s.L, &cValues[0], C.int(len(values)))
|
||||
|
||||
for i := range values {
|
||||
C.free(unsafe.Pointer(cValues[i]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchPushBoolArray creates and pushes a bool array in a single C call
|
||||
func (s *State) BatchPushBoolArray(values []bool) error {
|
||||
if len(values) == 0 {
|
||||
s.CreateTable(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
cValues := make([]C.int, len(values))
|
||||
for i, v := range values {
|
||||
if v {
|
||||
cValues[i] = 1
|
||||
} else {
|
||||
cValues[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
C.batch_push_bool_array(s.L, &cValues[0], C.int(len(values)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchExtractIntArray extracts an entire int array in a single C call
|
||||
func (s *State) BatchExtractIntArray(index, length int) ([]int, error) {
|
||||
if length <= 0 {
|
||||
return []int{}, nil
|
||||
}
|
||||
|
||||
buffer := make([]C.int, length)
|
||||
C.batch_extract_int_array(s.L, C.int(index), &buffer[0], C.int(length))
|
||||
|
||||
result := make([]int, length)
|
||||
for i := range length {
|
||||
result[i] = int(buffer[i])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BatchExtractFloatArray extracts an entire float array in a single C call
|
||||
func (s *State) BatchExtractFloatArray(index, length int) ([]float64, error) {
|
||||
if length <= 0 {
|
||||
return []float64{}, nil
|
||||
}
|
||||
|
||||
buffer := make([]C.double, length)
|
||||
C.batch_extract_float_array(s.L, C.int(index), &buffer[0], C.int(length))
|
||||
|
||||
result := make([]float64, length)
|
||||
for i := range length {
|
||||
result[i] = float64(buffer[i])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BatchExtractStringArray extracts an entire string array in a single C call
|
||||
func (s *State) BatchExtractStringArray(index, length int) ([]string, error) {
|
||||
if length <= 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
buffer := make([]*C.char, length)
|
||||
C.batch_extract_string_array(s.L, C.int(index), &buffer[0], C.int(length))
|
||||
|
||||
result := make([]string, length)
|
||||
for i := range length {
|
||||
result[i] = C.GoString(buffer[i])
|
||||
C.free(unsafe.Pointer(buffer[i]))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BatchExtractBoolArray extracts an entire bool array in a single C call
|
||||
func (s *State) BatchExtractBoolArray(index, length int) ([]bool, error) {
|
||||
if length <= 0 {
|
||||
return []bool{}, nil
|
||||
}
|
||||
|
||||
buffer := make([]C.int, length)
|
||||
C.batch_extract_bool_array(s.L, C.int(index), &buffer[0], C.int(length))
|
||||
|
||||
result := make([]bool, length)
|
||||
for i := range length {
|
||||
result[i] = buffer[i] != 0
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BatchTableBuilder provides batched table building operations
|
||||
type BatchTableBuilder struct {
|
||||
state *State
|
||||
index int
|
||||
stringFields map[string]string
|
||||
numberFields map[string]float64
|
||||
boolFields map[string]bool
|
||||
otherFields map[string]any
|
||||
}
|
||||
|
||||
// NewBatchTableBuilder creates a table builder that batches operations
|
||||
func (s *State) NewBatchTableBuilder() *BatchTableBuilder {
|
||||
s.NewTable()
|
||||
return &BatchTableBuilder{
|
||||
state: s,
|
||||
index: s.GetTop(),
|
||||
stringFields: make(map[string]string),
|
||||
numberFields: make(map[string]float64),
|
||||
boolFields: make(map[string]bool),
|
||||
otherFields: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
// SetString queues a string field for batch setting
|
||||
func (tb *BatchTableBuilder) SetString(key, value string) *BatchTableBuilder {
|
||||
tb.stringFields[key] = value
|
||||
return tb
|
||||
}
|
||||
|
||||
// SetNumber queues a number field for batch setting
|
||||
func (tb *BatchTableBuilder) SetNumber(key string, value float64) *BatchTableBuilder {
|
||||
tb.numberFields[key] = value
|
||||
return tb
|
||||
}
|
||||
|
||||
// SetBool queues a boolean field for batch setting
|
||||
func (tb *BatchTableBuilder) SetBool(key string, value bool) *BatchTableBuilder {
|
||||
tb.boolFields[key] = value
|
||||
return tb
|
||||
}
|
||||
|
||||
// SetNil sets a nil field immediately
|
||||
func (tb *BatchTableBuilder) SetNil(key string) *BatchTableBuilder {
|
||||
tb.state.PushNil()
|
||||
tb.state.SetField(tb.index, key)
|
||||
return tb
|
||||
}
|
||||
|
||||
// SetTable sets a table field immediately
|
||||
func (tb *BatchTableBuilder) SetTable(key string, value any) *BatchTableBuilder {
|
||||
tb.otherFields[key] = value
|
||||
return tb
|
||||
}
|
||||
|
||||
// SetArray sets an array field immediately
|
||||
func (tb *BatchTableBuilder) SetArray(key string, values []any) *BatchTableBuilder {
|
||||
tb.otherFields[key] = values
|
||||
return tb
|
||||
}
|
||||
|
||||
// Build executes all batched operations and finalizes the table
|
||||
func (tb *BatchTableBuilder) Build() error {
|
||||
// Batch string fields
|
||||
if len(tb.stringFields) > 0 {
|
||||
if err := tb.state.BatchSetStringFields(tb.index, tb.stringFields); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Batch number fields
|
||||
if len(tb.numberFields) > 0 {
|
||||
if err := tb.state.BatchSetNumberFields(tb.index, tb.numberFields); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Batch boolean fields
|
||||
if len(tb.boolFields) > 0 {
|
||||
if err := tb.state.BatchSetBoolFields(tb.index, tb.boolFields); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Individual operations for complex types
|
||||
for key, value := range tb.otherFields {
|
||||
if err := tb.state.PushValue(value); err != nil {
|
||||
return err
|
||||
}
|
||||
tb.state.SetField(tb.index, key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user