package luajit /* #include #include #include #include // 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; } // Batch global variable operations int batch_set_globals(lua_State *L, char **names, char **values, int count) { for (int i = 0; i < count; i++) { lua_pushstring(L, values[i]); lua_setfield(L, LUA_GLOBALSINDEX, names[i]); } return 0; } int batch_get_globals(lua_State *L, char **names, int count) { for (int i = 0; i < count; i++) { lua_getfield(L, LUA_GLOBALSINDEX, names[i]); } return 0; } // Batch table field reading int batch_get_table_fields(lua_State *L, int table_idx, char **keys, int count) { for (int i = 0; i < count; i++) { lua_getfield(L, table_idx, keys[i]); } return 0; } // Batch type checking int batch_check_types(lua_State *L, int *indices, int *expected_types, int count) { for (int i = 0; i < count; i++) { int actual = lua_type(L, indices[i]); if (actual != expected_types[i]) { return i + 1; // Return 1-based index of first mismatch } } return 0; // All types match } // Batch stack value pushes int batch_push_mixed_values(lua_State *L, void **values, int *types, int count) { for (int i = 0; i < count; i++) { switch (types[i]) { case LUA_TNIL: lua_pushnil(L); break; case LUA_TBOOLEAN: lua_pushboolean(L, *(int*)values[i]); break; case LUA_TNUMBER: lua_pushnumber(L, *(double*)values[i]); break; case LUA_TSTRING: lua_pushstring(L, (char*)values[i]); break; } } return 0; } // Batch function registration int batch_register_functions(lua_State *L, char **names, lua_CFunction *funcs, int count) { for (int i = 0; i < count; i++) { lua_pushcfunction(L, funcs[i]); lua_setglobal(L, names[i]); } return 0; } // Batch package path operations int batch_add_package_paths(lua_State *L, char **paths, int count) { lua_getglobal(L, "package"); lua_getfield(L, -1, "path"); const char *current = lua_tostring(L, -1); size_t total_len = strlen(current) + 1; for (int i = 0; i < count; i++) { total_len += strlen(paths[i]) + 1; // +1 for semicolon } char *new_path = malloc(total_len + 1); strcpy(new_path, current); for (int i = 0; i < count; i++) { strcat(new_path, ";"); strcat(new_path, paths[i]); } lua_pushstring(L, new_path); lua_setfield(L, -3, "path"); lua_pop(L, 2); // Remove package table and old path free(new_path); return 0; } // Batch error context building void batch_build_error_context(lua_State *L, char **context_parts, int count, char *output, size_t max_len) { size_t pos = 0; for (int i = 0; i < count && pos < max_len - 1; i++) { size_t part_len = strlen(context_parts[i]); if (pos + part_len + 1 < max_len) { if (i > 0) output[pos++] = ' '; memcpy(output + pos, context_parts[i], part_len); pos += part_len; } } output[pos] = '\0'; } */ import "C" import ( "fmt" "strings" "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 } // BatchSetGlobals sets multiple global variables in one C call func (s *State) BatchSetGlobals(globals map[string]string) error { if len(globals) == 0 { return nil } names := make([]*C.char, len(globals)) values := make([]*C.char, len(globals)) i := 0 for name, value := range globals { names[i] = C.CString(name) values[i] = C.CString(value) i++ } C.batch_set_globals(s.L, &names[0], &values[0], C.int(len(globals))) for j := range len(globals) { C.free(unsafe.Pointer(names[j])) C.free(unsafe.Pointer(values[j])) } return nil } // BatchGetGlobals gets multiple global variables, leaving them on stack func (s *State) BatchGetGlobals(names []string) error { if len(names) == 0 { return nil } cNames := make([]*C.char, len(names)) for i, name := range names { cNames[i] = C.CString(name) } C.batch_get_globals(s.L, &cNames[0], C.int(len(names))) for i := range names { C.free(unsafe.Pointer(cNames[i])) } return nil } // BatchGetTableFields gets multiple fields from a table, leaving them on stack func (s *State) BatchGetTableFields(tableIndex int, keys []string) error { if len(keys) == 0 { return nil } cKeys := make([]*C.char, len(keys)) for i, key := range keys { cKeys[i] = C.CString(key) } C.batch_get_table_fields(s.L, C.int(tableIndex), &cKeys[0], C.int(len(keys))) for i := range keys { C.free(unsafe.Pointer(cKeys[i])) } return nil } // BatchCheckTypes validates multiple stack positions have expected types func (s *State) BatchCheckTypes(checks []TypeCheck) error { if len(checks) == 0 { return nil } indices := make([]C.int, len(checks)) expectedTypes := make([]C.int, len(checks)) for i, check := range checks { indices[i] = C.int(check.Index) expectedTypes[i] = C.int(check.ExpectedType) } result := C.batch_check_types(s.L, &indices[0], &expectedTypes[0], C.int(len(checks))) if result != 0 { check := checks[result-1] actual := s.GetType(check.Index) return fmt.Errorf("type mismatch at index %d: expected %s, got %s", check.Index, check.ExpectedType, actual) } return nil } // BatchAddPackagePaths adds multiple paths to package.path in one operation func (s *State) BatchAddPackagePaths(paths []string) error { if len(paths) == 0 { return nil } cPaths := make([]*C.char, len(paths)) for i, path := range paths { normalizedPath := strings.ReplaceAll(path, "\\", "/") cPaths[i] = C.CString(normalizedPath) } C.batch_add_package_paths(s.L, &cPaths[0], C.int(len(paths))) for i := range paths { C.free(unsafe.Pointer(cPaths[i])) } return nil } // TypeCheck represents a type validation check type TypeCheck struct { Index int ExpectedType LuaType } // BatchValuePusher accumulates values for efficient batch pushing type BatchValuePusher struct { state *State values []any } // NewBatchValuePusher creates a new batch value pusher func (s *State) NewBatchValuePusher() *BatchValuePusher { return &BatchValuePusher{ state: s, values: make([]any, 0, 8), } } // Add queues a value for batch pushing func (bvp *BatchValuePusher) Add(value any) *BatchValuePusher { bvp.values = append(bvp.values, value) return bvp } // Push executes the batch push operation func (bvp *BatchValuePusher) Push() error { if len(bvp.values) == 0 { return nil } // Separate by type for optimal batching var strings []string var numbers []float64 var bools []bool var others []any for _, v := range bvp.values { switch val := v.(type) { case string: if len(strings) == len(numbers)+len(bools)+len(others) { strings = append(strings, val) } else { others = append(others, val) } case int: if len(numbers) == len(strings)+len(bools)+len(others) { numbers = append(numbers, float64(val)) } else { others = append(others, val) } case float64: if len(numbers) == len(strings)+len(bools)+len(others) { numbers = append(numbers, val) } else { others = append(others, val) } case bool: if len(bools) == len(strings)+len(numbers)+len(others) { bools = append(bools, val) } else { others = append(others, val) } default: others = append(others, val) } } // Push in batches when beneficial if len(strings) > 2 && len(numbers) == 0 && len(bools) == 0 && len(others) == 0 { return bvp.pushStringBatch(strings) } if len(numbers) > 2 && len(strings) == 0 && len(bools) == 0 && len(others) == 0 { return bvp.pushNumberBatch(numbers) } if len(bools) > 2 && len(strings) == 0 && len(numbers) == 0 && len(others) == 0 { return bvp.pushBoolBatch(bools) } // Fall back to individual pushes for mixed types for _, value := range bvp.values { if err := bvp.state.PushValue(value); err != nil { return err } } return nil } func (bvp *BatchValuePusher) pushStringBatch(strings []string) error { cValues := make([]*C.char, len(strings)) for i, s := range strings { cValues[i] = C.CString(s) } for i, cstr := range cValues { C.lua_pushstring(bvp.state.L, cstr) C.free(unsafe.Pointer(cstr)) _ = i // Use i to avoid unused variable } return nil } func (bvp *BatchValuePusher) pushNumberBatch(numbers []float64) error { for _, n := range numbers { C.lua_pushnumber(bvp.state.L, C.lua_Number(n)) } return nil } func (bvp *BatchValuePusher) pushBoolBatch(bools []bool) error { for _, b := range bools { if b { C.lua_pushboolean(bvp.state.L, 1) } else { C.lua_pushboolean(bvp.state.L, 0) } } return nil } // BatchTableReader efficiently reads multiple table configurations type BatchTableReader struct { state *State index int } // NewBatchTableReader creates a table reader for efficient field access func (s *State) NewBatchTableReader(index int) *BatchTableReader { return &BatchTableReader{ state: s, index: s.absIndex(index), } } // ReadFields reads multiple fields and returns them as a map func (btr *BatchTableReader) ReadFields(keys []string) (map[string]any, error) { if len(keys) == 0 { return make(map[string]any), nil } // Use batch operation for many fields if len(keys) > 3 { startTop := btr.state.GetTop() if err := btr.state.BatchGetTableFields(btr.index, keys); err != nil { return nil, err } result := make(map[string]any, len(keys)) for i, key := range keys { if value, err := btr.state.ToValue(startTop + i + 1); err == nil { result[key] = value } } btr.state.SetTop(startTop) // Restore stack return result, nil } // Individual access for few fields result := make(map[string]any, len(keys)) for _, key := range keys { btr.state.GetField(btr.index, key) if value, err := btr.state.ToValue(-1); err == nil { result[key] = value } btr.state.Pop(1) } return result, nil } // BatchGlobalManager manages multiple global operations efficiently type BatchGlobalManager struct { state *State pendingSets map[string]string pendingGets []string } // NewBatchGlobalManager creates a global variable manager func (s *State) NewBatchGlobalManager() *BatchGlobalManager { return &BatchGlobalManager{ state: s, pendingSets: make(map[string]string), pendingGets: make([]string, 0), } } // QueueSet queues a global variable for batch setting func (bgm *BatchGlobalManager) QueueSet(name, value string) *BatchGlobalManager { bgm.pendingSets[name] = value return bgm } // QueueGet queues a global variable for batch getting func (bgm *BatchGlobalManager) QueueGet(name string) *BatchGlobalManager { bgm.pendingGets = append(bgm.pendingGets, name) return bgm } // Execute performs all queued operations func (bgm *BatchGlobalManager) Execute() (map[string]any, error) { // Execute batch sets if len(bgm.pendingSets) > 0 { if err := bgm.state.BatchSetGlobals(bgm.pendingSets); err != nil { return nil, err } } // Execute batch gets var result map[string]any if len(bgm.pendingGets) > 0 { startTop := bgm.state.GetTop() if err := bgm.state.BatchGetGlobals(bgm.pendingGets); err != nil { return nil, err } result = make(map[string]any, len(bgm.pendingGets)) for i, name := range bgm.pendingGets { if value, err := bgm.state.ToValue(startTop + i + 1); err == nil { result[name] = value } } bgm.state.SetTop(startTop) // Restore stack } return result, nil }