Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/src/state/lua_state_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class LuaStateImpl implements LuaState, LuaVM {
LuaStack? _stack = LuaStack();

/// 注册表
LuaTable? registry = LuaTable(0, 0);
LuaTable? registry = LuaTable();

LuaStateImpl() {
registry!.put(lua_ridx_globals, LuaTable(0, 0));
registry!.put(lua_ridx_globals, LuaTable());
LuaStack stack = LuaStack();
stack.state = this;
_pushLuaStack(stack);
Expand Down Expand Up @@ -427,7 +427,7 @@ class LuaStateImpl implements LuaState, LuaVM {

@override
void createTable(int nArr, int nRec) {
_stack!.push(LuaTable(nArr, nRec));
_stack!.push(LuaTable());
}

@override
Expand Down
178 changes: 39 additions & 139 deletions lib/src/state/lua_table.dart
Original file line number Diff line number Diff line change
@@ -1,169 +1,69 @@
import 'dart:collection';

import '../number/lua_number.dart';
import 'package:lua_dardo/src/state/table/lua_table_array.dart';
import 'package:lua_dardo/src/state/table/lua_table_keys.dart';
import 'package:lua_dardo/src/state/table/lua_table_map.dart';

class LuaTable {
/// 元表
LuaTable? metatable;
List<Object?>? arr;
Map<Object?, Object>? map;

// used by next()
Map<Object?, Object?>? keys;
Object? lastKey;
late bool changed;

LuaTable(int nArr, int nRec) {
if (nArr > 0) {
// arr = List<Object>(nArr);
arr = <Object?>[];
}
if (nRec > 0) {
// map = Map<Object, Object>(nRec);
map = HashMap<Object?, Object>();
}
}

bool hasMetafield(String fieldName) {
return metatable != null && metatable!.get(fieldName) != null;
}

int length() {
return arr == null ? 0 : arr!.length;
}

Object? get(Object? key) {
key = floatToInteger(key);

if (arr != null && key is int) {
int idx = key;
if (idx >= 1 && idx <= arr!.length) {
return arr![idx - 1];
}
}
final LuaTableArray arr = LuaTableArray();
final LuaTableMap map = LuaTableMap();
final LuaTableKeys keys = LuaTableKeys();

return map != null ? map![key] : null;
}
bool hasMetafield(String fieldName) => metatable?.get(fieldName) != null;

void put(Object? key, Object? val) {
if (key == null) {
throw Exception("table index is nil!");
}

if (key is double && key.isNaN) {
throw Exception("table index is NaN!");
}

key = floatToInteger(key);
if (key is int) {
int idx = key;
if (idx >= 1) {
if (arr == null) {
arr = <Object?>[];
}

int arrLen = arr!.length;
if (idx <= arrLen) {
arr![idx-1] = val;
if (idx == arrLen && val == null) {
shrinkArray();
}
return;
}
if (idx == arrLen + 1) {
if (map != null) {
map!.remove(key);
}
if (val != null) {
arr!.add(val);
expandArray();
}
return;
}
}
}

if (val != null) {
if (map == null) {
map = HashMap<Object?, Object>();
}
map![key] = val;
if (val == null) {
_remove(key);
} else if (arr.isArrayIndex(key)) {
arr[key] = val;
} else if (arr.isArrayIndex(key, forInsert: true)) {
arr[key] = val;
_expandArray();
} else {
if (map != null) {
map!.remove(key);
}
map[key] = val;
}

keys.update(arr.length, map.keys);
}

Object? floatToInteger(Object? key) {
if (key is double) {
double f = key;
if (LuaNumber.isInteger(f)) {
return f.toInt();
}
void _remove(Object key) {
if (arr.isArrayIndex(key)) {
arr.removeAt(key);
} else {
map.remove(key);
}
return key;
}

void shrinkArray() {
for (int i = arr!.length - 1; i >= 0; i--) {
if (arr![i] == null) {
arr!.removeAt(i);
}
void _expandArray() {
int key = arr.length + 1;
Object? value = map[key];
while (value != null) {
arr[key] = value;
map.remove(key);

key++;
value = map[key];
}
}

void expandArray() {
if (map != null) {
for (int idx = arr!.length + 1; ; idx++) {
Object? val = map!.remove(idx);
if (val != null) {
arr!.add(val);
} else {
break;
}
}
Object? get(Object? key) {
if (key != null) {
return (arr.isArrayIndex(key)) ? arr[key] : map[key];
}
return null;
}

Object? nextKey(Object? key) {
if (keys == null || (key == null && changed)) {
initKeys();
changed = false;
}
Object? nextKey(Object? key) => keys.nextKey(key);

Object? nextKey = keys![key];
if (nextKey == null && key != null && key != lastKey) {
throw Exception("invalid key to 'next'");
}
int length() => arr.length;

return nextKey;
}

void initKeys() {
if (keys == null) {
keys = HashMap<Object?, Object?>();
} else {
keys!.clear();
}
Object? key = null;
if (arr != null) {
for (int i = 0; i < arr!.length; i++) {
if (arr![i] != null) {
int nextKey = i + 1;
keys![key] = nextKey;
key = nextKey;
}
}
}
if (map != null) {
for (Object? k in map!.keys) {
Object? v = map![k];
if (v != null) {
keys![key] = k;
key = k;
}
}
}
lastKey = key;
}
}
}
49 changes: 49 additions & 0 deletions lib/src/state/table/lua_table_array.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

import 'package:lua_dardo/src/number/lua_number.dart';

class LuaTableArray {

List<Object>? _arr;

bool isArrayIndex(Object key, {bool forInsert = false}) {
int idx = _floatToIndex(key);
bool canInsert = forInsert && idx == length;
return idx >= 0 && (idx < length || canInsert);
}

void operator []= (Object key, Object value) {
int idx = _floatToIndex(key);
if (idx < length) {
_initializedArray[idx] = value;
} else {
_initializedArray.add(value);
}
}

Object operator [] (Object key) {
int idx = _floatToIndex(key);
return _initializedArray[idx];
}

void removeAt(Object key) {
int idx = _floatToIndex(key);
_initializedArray.removeAt(idx);
}

int _floatToIndex(Object key) {
int intKey = (key is double && LuaNumber.isInteger(key))
? key.toInt()
: (key is int) ? key : -1;
return intKey -1;
}

int get length => (_arr != null) ? _initializedArray.length : 0;

List<Object> get _initializedArray {
if (_arr == null) {
_arr = [];
}
return _arr!;
}

}
51 changes: 51 additions & 0 deletions lib/src/state/table/lua_table_keys.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

class LuaTableKeys {

final Map<Object?, Object> _nextKeys = {};

Object? lastKey;

int _arrLength = 0;
Iterable<Object> _keys = [];
bool _changed = false;

void update(int arrLength, Iterable<Object> keys) {
_arrLength = arrLength;
_keys = keys;
_changed = true;
}

Object? nextKey(Object? key) {
if (_changed) {
regenerate();
}

Object? nextKey = _nextKeys[key];

if (nextKey == null && key != null && key != lastKey) {
throw Exception("invalid key to 'next'");
}

return nextKey;
}

void regenerate() {
_nextKeys.clear();

Object? key = null;

for (int i=1; i < _arrLength; i++) {
_nextKeys[key] = i;
key = i+1;
}

for (Object nextKey in _keys) {
_nextKeys[key] = nextKey;
key = nextKey;
}

lastKey = key;
_changed = false;
}

}
26 changes: 26 additions & 0 deletions lib/src/state/table/lua_table_map.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

class LuaTableMap {

Map<Object, Object>? _map;

void operator []= (Object key, Object value) {
_initializedMap[key] = value;
}

Object? operator [] (Object key) => _initializedMap[key];

void remove(Object key) => _initializedMap.remove(key);

Iterable<Object> get keys => (_map != null)
? _initializedMap.keys
: Iterable.empty();

Map<Object, Object> get _initializedMap {
if (_map == null) {
_map = {};
}

return _map!;
}

}
Loading