Weak table implementation.
This commit is contained in:
@@ -119,7 +119,7 @@ public class DumpState {
|
|||||||
dumpInt(n);
|
dumpInt(n);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
final LValue o = f.k[i];
|
final LValue o = f.k[i];
|
||||||
if (o == LNil.NIL) {
|
if (o.isNil()) {
|
||||||
writer.write(Lua.LUA_TNIL);
|
writer.write(Lua.LUA_TNIL);
|
||||||
// do nothing more
|
// do nothing more
|
||||||
} else if (o instanceof LBoolean) {
|
} else if (o instanceof LBoolean) {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public class BaseLib extends LFunction {
|
|||||||
"tostring",
|
"tostring",
|
||||||
"unpack",
|
"unpack",
|
||||||
"next",
|
"next",
|
||||||
|
"_inext", // not public
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int INSTALL = 0;
|
private static final int INSTALL = 0;
|
||||||
@@ -81,10 +82,16 @@ public class BaseLib extends LFunction {
|
|||||||
private static final int TOSTRING = 21;
|
private static final int TOSTRING = 21;
|
||||||
private static final int UNPACK = 22;
|
private static final int UNPACK = 22;
|
||||||
private static final int NEXT = 23;
|
private static final int NEXT = 23;
|
||||||
|
private static final int INEXT = 24;
|
||||||
|
|
||||||
|
private static LFunction next;
|
||||||
|
private static LFunction inext;
|
||||||
|
|
||||||
public static void install(LTable globals) {
|
public static void install(LTable globals) {
|
||||||
for ( int i=1; i<NAMES.length; i++ )
|
for ( int i=1, n=NAMES.length; i<n; i++ )
|
||||||
globals.put( NAMES[i], new BaseLib(i) );
|
globals.put( NAMES[i], new BaseLib(i) );
|
||||||
|
next = new BaseLib(NEXT);
|
||||||
|
inext = new BaseLib(INEXT);
|
||||||
globals.put("_VERSION", new LString("Lua 5.1"));
|
globals.put("_VERSION", new LString("Lua 5.1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,13 +149,23 @@ public class BaseLib extends LFunction {
|
|||||||
vm.resettop();
|
vm.resettop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PAIRS:
|
case IPAIRS:
|
||||||
case IPAIRS: {
|
case PAIRS: {
|
||||||
checkargtype(vm,2,Lua.LUA_TTABLE);
|
checkargtype(vm,2,Lua.LUA_TTABLE);
|
||||||
LTable v = vm.totable(2);
|
LTable t = vm.totable(2);
|
||||||
LValue r = v.luaPairs(id==PAIRS);
|
|
||||||
vm.resettop();
|
vm.resettop();
|
||||||
vm.pushlvalue( r );
|
vm.pushjavafunction( (id==IPAIRS)? inext: next );
|
||||||
|
vm.pushlvalue( t );
|
||||||
|
vm.pushnil();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INEXT:
|
||||||
|
case NEXT: {
|
||||||
|
checkargtype(vm,2,Lua.LUA_TTABLE);
|
||||||
|
LTable t = vm.totable(2);
|
||||||
|
LValue v = vm.topointer(3);
|
||||||
|
vm.resettop();
|
||||||
|
t.next(vm,v,(id==INEXT));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GETMETATABLE: {
|
case GETMETATABLE: {
|
||||||
@@ -358,14 +375,6 @@ public class BaseLib extends LFunction {
|
|||||||
vm.pushlvalue(list.get(k));
|
vm.pushlvalue(list.get(k));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NEXT: {
|
|
||||||
checkargtype(vm,2,Lua.LUA_TTABLE);
|
|
||||||
LTable t = vm.totable(2);
|
|
||||||
LValue v = vm.topointer(3);
|
|
||||||
vm.resettop();
|
|
||||||
t.next(vm,v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
LuaState.vmerror( "bad base id" );
|
LuaState.vmerror( "bad base id" );
|
||||||
}
|
}
|
||||||
@@ -472,7 +481,7 @@ public class BaseLib extends LFunction {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LValue v = vm.topointer(2);
|
LValue v = vm.topointer(2);
|
||||||
if ( v == LNil.NIL )
|
if ( v.isNil() )
|
||||||
break;
|
break;
|
||||||
LString s = v.luaAsString();
|
LString s = v.luaAsString();
|
||||||
s.write(baos, 0, s.length());
|
s.write(baos, 0, s.length());
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ public class PackageLib extends LFunction {
|
|||||||
e = fname.m_length;
|
e = fname.m_length;
|
||||||
LString key = fname.substring(b, e);
|
LString key = fname.substring(b, e);
|
||||||
LValue val = table.get(key);
|
LValue val = table.get(key);
|
||||||
if ( val == LNil.NIL ) { /* no such field? */
|
if ( val.isNil() ) { /* no such field? */
|
||||||
LTable field = new LTable(); /* new table for field */
|
LTable field = new LTable(); /* new table for field */
|
||||||
table.put(key, field);
|
table.put(key, field);
|
||||||
table = field;
|
table = field;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.luaj.vm.LFunction;
|
|||||||
import org.luaj.vm.LString;
|
import org.luaj.vm.LString;
|
||||||
import org.luaj.vm.LTable;
|
import org.luaj.vm.LTable;
|
||||||
import org.luaj.vm.LValue;
|
import org.luaj.vm.LValue;
|
||||||
|
import org.luaj.vm.LWeakTable;
|
||||||
import org.luaj.vm.LuaState;
|
import org.luaj.vm.LuaState;
|
||||||
|
|
||||||
|
|
||||||
@@ -205,7 +206,7 @@ public class TableLib extends LFunction {
|
|||||||
vm.resettop();
|
vm.resettop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LuaState.vmerror( "bad table id" );
|
LuaState.vmerror( "bad table id" );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ public final class LNil extends LValue {
|
|||||||
return luaGetTypeName();
|
return luaGetTypeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNil() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean toJavaBoolean() {
|
public boolean toJavaBoolean() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,33 +57,35 @@ public class LTable extends LValue {
|
|||||||
* Elements of m_hashKeys are never LNil.NIL - they are null to indicate
|
* Elements of m_hashKeys are never LNil.NIL - they are null to indicate
|
||||||
* the hash slot is empty and some non-null, non-nil value otherwise.
|
* the hash slot is empty and some non-null, non-nil value otherwise.
|
||||||
*/
|
*/
|
||||||
private LValue[] m_hashKeys;
|
protected LValue[] m_hashKeys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Values in the hash part. Must be null when m_hashKeys is null and equal
|
* Values in the hash part. Must be null when m_hashKeys is null and equal
|
||||||
* in size otherwise.
|
* in size otherwise.
|
||||||
*/
|
*/
|
||||||
private LValue[] m_hashValues;
|
protected LValue[] m_hashValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* m_hashEntries is the number of slots that are used. Must always be less
|
* m_hashEntries is the number of slots that are used. Must always be less
|
||||||
* than m_hashKeys.length.
|
* than m_hashKeys.length.
|
||||||
*/
|
*/
|
||||||
private int m_hashEntries;
|
protected int m_hashEntries;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of values to store the "array part" of the table, that is the
|
* Array of values to store the "array part" of the table, that is the
|
||||||
* entries with positive integer keys. Elements must never be null: "empty"
|
* entries with positive integer keys. Elements must never be null: "empty"
|
||||||
* slots are set to LNil.NIL.
|
* slots are set to LNil.NIL.
|
||||||
*/
|
*/
|
||||||
private LValue[] m_vector;
|
protected LValue[] m_vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of values in m_vector that non-nil.
|
* Number of values in m_vector that non-nil.
|
||||||
*/
|
*/
|
||||||
private int m_arrayEntries;
|
protected int m_arrayEntries;
|
||||||
|
|
||||||
private LTable m_metatable;
|
private LTable m_metatable;
|
||||||
|
|
||||||
|
private static final int INVALID_KEY_TO_NEXT = -2;
|
||||||
|
|
||||||
/** Construct an empty LTable with no initial capacity. */
|
/** Construct an empty LTable with no initial capacity. */
|
||||||
public LTable() {
|
public LTable() {
|
||||||
@@ -123,7 +125,7 @@ public class LTable extends LValue {
|
|||||||
if ( key.isInteger() ) {
|
if ( key.isInteger() ) {
|
||||||
// call the integer-specific put method
|
// call the integer-specific put method
|
||||||
put( key.toJavaInt(), val );
|
put( key.toJavaInt(), val );
|
||||||
} else if ( val == null || val == LNil.NIL ) {
|
} else if ( val == null || val.isNil() ) {
|
||||||
// Remove the key if the value is nil. This comes after the check
|
// Remove the key if the value is nil. This comes after the check
|
||||||
// for an integer key so that values are properly removed from
|
// for an integer key so that values are properly removed from
|
||||||
// the array part.
|
// the array part.
|
||||||
@@ -159,7 +161,7 @@ public class LTable extends LValue {
|
|||||||
* any.
|
* any.
|
||||||
*/
|
*/
|
||||||
public void put( int key, LValue value ) {
|
public void put( int key, LValue value ) {
|
||||||
if (value == null || value == LNil.NIL) {
|
if (value == null || value.isNil()) {
|
||||||
remove( key );
|
remove( key );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -167,7 +169,7 @@ public class LTable extends LValue {
|
|||||||
final int index = key - 1;
|
final int index = key - 1;
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if ( index < m_vector.length ) {
|
if ( index < m_vector.length ) {
|
||||||
if ( m_vector[index] == LNil.NIL ) {
|
if ( m_vector[index].isNil() ) {
|
||||||
++m_arrayEntries;
|
++m_arrayEntries;
|
||||||
}
|
}
|
||||||
m_vector[index] = value;
|
m_vector[index] = value;
|
||||||
@@ -231,8 +233,7 @@ public class LTable extends LValue {
|
|||||||
if ( m_vector.length > 0 && key.isInteger() ) {
|
if ( m_vector.length > 0 && key.isInteger() ) {
|
||||||
final int index = key.toJavaInt() - 1;
|
final int index = key.toJavaInt() - 1;
|
||||||
if ( index >= 0 && index < m_vector.length ) {
|
if ( index >= 0 && index < m_vector.length ) {
|
||||||
final LValue v = m_vector[index];
|
return ! m_vector[index].isNil();
|
||||||
return v != LNil.NIL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( m_hashKeys == null )
|
if ( m_hashKeys == null )
|
||||||
@@ -243,7 +244,7 @@ public class LTable extends LValue {
|
|||||||
|
|
||||||
public void luaGetTable(LuaState vm, LValue table, LValue key) {
|
public void luaGetTable(LuaState vm, LValue table, LValue key) {
|
||||||
LValue v = get(key);
|
LValue v = get(key);
|
||||||
if ( v == LNil.NIL && m_metatable != null ) {
|
if ( v.isNil() && m_metatable != null ) {
|
||||||
super.luaGetTable( vm, table, key );
|
super.luaGetTable( vm, table, key );
|
||||||
} else {
|
} else {
|
||||||
vm.pushlvalue(v);
|
vm.pushlvalue(v);
|
||||||
@@ -264,8 +265,8 @@ public class LTable extends LValue {
|
|||||||
*/
|
*/
|
||||||
public int luaLength() {
|
public int luaLength() {
|
||||||
for ( int i = Math.max( 0, m_arrayEntries-1 ); i < m_vector.length; ++i ) {
|
for ( int i = Math.max( 0, m_arrayEntries-1 ); i < m_vector.length; ++i ) {
|
||||||
if ( m_vector[i] != LNil.NIL &&
|
if ( ! m_vector[i].isNil() &&
|
||||||
( i+1 == m_vector.length || m_vector[i+1] == LNil.NIL ) ) {
|
( i+1 == m_vector.length || m_vector[i+1].isNil() ) ) {
|
||||||
return i+1;
|
return i+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,15 +279,24 @@ public class LTable extends LValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Valid for tables */
|
/** Valid for tables */
|
||||||
public void luaSetMetatable(LValue metatable) {
|
public LValue luaSetMetatable(LValue metatable) {
|
||||||
if ( m_metatable != null && m_metatable.containsKey(TM_METATABLE) )
|
if ( m_metatable != null && m_metatable.containsKey(TM_METATABLE) )
|
||||||
throw new LuaErrorException("cannot change a protected metatable");
|
throw new LuaErrorException("cannot change a protected metatable");
|
||||||
if ( metatable == null || metatable == LNil.NIL )
|
if ( metatable == null || metatable.isNil() )
|
||||||
this.m_metatable = null;
|
this.m_metatable = null;
|
||||||
else if ( metatable.luaGetType() == Lua.LUA_TTABLE )
|
else if ( metatable.luaGetType() == Lua.LUA_TTABLE ) {
|
||||||
this.m_metatable = (LTable) metatable;
|
LTable t = (LTable) metatable;
|
||||||
|
LValue m = t.get(TM_MODE);
|
||||||
|
if ( "v".equals(m.toJavaString()) ) {
|
||||||
|
LTable n = new LWeakTable(this);
|
||||||
|
n.m_metatable = t;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
this.m_metatable = t;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw new LuaErrorException("nil or table expected, got "+metatable.luaGetTypeName());
|
throw new LuaErrorException("nil or table expected, got "+metatable.luaGetTypeName());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toJavaString() {
|
public String toJavaString() {
|
||||||
@@ -296,47 +306,6 @@ public class LTable extends LValue {
|
|||||||
public int luaGetType() {
|
public int luaGetType() {
|
||||||
return Lua.LUA_TTABLE;
|
return Lua.LUA_TTABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Valid for tables */
|
|
||||||
public LValue luaPairs(boolean isPairs) {
|
|
||||||
return new LTableIterator(isPairs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Iterator for tables */
|
|
||||||
private final class LTableIterator extends LFunction {
|
|
||||||
private int arrayIndex;
|
|
||||||
private int hashIndex;
|
|
||||||
private final boolean isPairs;
|
|
||||||
|
|
||||||
private LTableIterator(boolean isPairs) {
|
|
||||||
this.arrayIndex = 0;
|
|
||||||
this.hashIndex = 0;
|
|
||||||
this.isPairs = isPairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform a lua call
|
|
||||||
public boolean luaStackCall(LuaState vm) {
|
|
||||||
vm.resettop();
|
|
||||||
int i;
|
|
||||||
while ( ( i = arrayIndex++ ) < m_vector.length ) {
|
|
||||||
if ( m_vector[i] != LNil.NIL ) {
|
|
||||||
vm.pushinteger( arrayIndex );
|
|
||||||
vm.pushlvalue( m_vector[ i ] );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( isPairs && (m_hashKeys != null) ) {
|
|
||||||
while ( ( i = hashIndex++ ) < m_hashKeys.length ) {
|
|
||||||
if ( m_hashKeys[i] != null ) {
|
|
||||||
vm.pushlvalue( m_hashKeys[i] );
|
|
||||||
vm.pushlvalue( m_hashValues[i] );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to get all the keys in this table in an array. Meant to be
|
* Helper method to get all the keys in this table in an array. Meant to be
|
||||||
@@ -349,7 +318,7 @@ public class LTable extends LValue {
|
|||||||
int out = 0;
|
int out = 0;
|
||||||
|
|
||||||
for ( int i = 0; i < m_vector.length; ++i ) {
|
for ( int i = 0; i < m_vector.length; ++i ) {
|
||||||
if ( m_vector[ i ] != LNil.NIL ) {
|
if ( ! m_vector[ i ].isNil() ) {
|
||||||
keys[ out++ ] = LInteger.valueOf( i + 1 );
|
keys[ out++ ] = LInteger.valueOf( i + 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,11 +334,11 @@ public class LTable extends LValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Remove the value in the table with the given integer key. */
|
/** Remove the value in the table with the given integer key. */
|
||||||
private void remove( int key ) {
|
protected void remove( int key ) {
|
||||||
if ( key > 0 ) {
|
if ( key > 0 ) {
|
||||||
final int index = key - 1;
|
final int index = key - 1;
|
||||||
if ( index < m_vector.length ) {
|
if ( index < m_vector.length ) {
|
||||||
if ( m_vector[ index ] != LNil.NIL ) {
|
if ( ! m_vector[ index ].isNil() ) {
|
||||||
m_vector[ index ] = LNil.NIL;
|
m_vector[ index ] = LNil.NIL;
|
||||||
--m_arrayEntries;
|
--m_arrayEntries;
|
||||||
}
|
}
|
||||||
@@ -383,7 +352,7 @@ public class LTable extends LValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove( LValue key ) {
|
protected void remove( LValue key ) {
|
||||||
if ( m_hashKeys != null ) {
|
if ( m_hashKeys != null ) {
|
||||||
int slot = findSlot( key );
|
int slot = findSlot( key );
|
||||||
clearSlot( slot );
|
clearSlot( slot );
|
||||||
@@ -522,7 +491,7 @@ public class LTable extends LValue {
|
|||||||
} else {
|
} else {
|
||||||
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
||||||
LValue v = m_vector[i];
|
LValue v = m_vector[i];
|
||||||
if ( v != LNil.NIL ) {
|
if ( ! v.isNil() ) {
|
||||||
if (checkLoadFactor())
|
if (checkLoadFactor())
|
||||||
rehash();
|
rehash();
|
||||||
final int slot = findSlot( i+1 );
|
final int slot = findSlot( i+1 );
|
||||||
@@ -557,7 +526,7 @@ public class LTable extends LValue {
|
|||||||
final int index = Math.max(0,pos==0? m_arrayEntries: pos-1);
|
final int index = Math.max(0,pos==0? m_arrayEntries: pos-1);
|
||||||
if ( m_arrayEntries + 1 > m_vector.length )
|
if ( m_arrayEntries + 1 > m_vector.length )
|
||||||
resize( ( m_arrayEntries + 1 ) * 2 );
|
resize( ( m_arrayEntries + 1 ) * 2 );
|
||||||
if ( m_vector[index] != LNil.NIL ) {
|
if ( ! m_vector[index].isNil() ) {
|
||||||
System.arraycopy(m_vector, index, m_vector, index+1, m_vector.length-1-index);
|
System.arraycopy(m_vector, index, m_vector, index+1, m_vector.length-1-index);
|
||||||
}
|
}
|
||||||
m_vector[index] = value;
|
m_vector[index] = value;
|
||||||
@@ -572,7 +541,7 @@ public class LTable extends LValue {
|
|||||||
public LValue luaRemovePos(int pos) {
|
public LValue luaRemovePos(int pos) {
|
||||||
if ( pos > m_arrayEntries ) {
|
if ( pos > m_arrayEntries ) {
|
||||||
LValue val = get( pos );
|
LValue val = get( pos );
|
||||||
if ( val != LNil.NIL )
|
if ( ! val.isNil() )
|
||||||
put( pos, LNil.NIL );
|
put( pos, LNil.NIL );
|
||||||
return val;
|
return val;
|
||||||
} else {
|
} else {
|
||||||
@@ -592,7 +561,7 @@ public class LTable extends LValue {
|
|||||||
LValue result = LInteger.valueOf(0);
|
LValue result = LInteger.valueOf(0);
|
||||||
|
|
||||||
for ( int i = m_vector.length - 1; i >= 0; i-- ) {
|
for ( int i = m_vector.length - 1; i >= 0; i-- ) {
|
||||||
if ( m_vector[i] != LNil.NIL ) {
|
if ( ! m_vector[i].isNil() ) {
|
||||||
result = LInteger.valueOf(i + 1);
|
result = LInteger.valueOf(i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -648,7 +617,7 @@ public class LTable extends LValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean compare(int i, int j, LuaState vm, LValue cmpfunc) {
|
private boolean compare(int i, int j, LuaState vm, LValue cmpfunc) {
|
||||||
if ( cmpfunc != LNil.NIL ) {
|
if ( ! cmpfunc.isNil() ) {
|
||||||
vm.pushlvalue(cmpfunc);
|
vm.pushlvalue(cmpfunc);
|
||||||
vm.pushlvalue(m_vector[i]);
|
vm.pushlvalue(m_vector[i]);
|
||||||
vm.pushlvalue(m_vector[j]);
|
vm.pushlvalue(m_vector[j]);
|
||||||
@@ -670,65 +639,77 @@ public class LTable extends LValue {
|
|||||||
/**
|
/**
|
||||||
* Leave key,value pair on top, or nil if at end of list.
|
* Leave key,value pair on top, or nil if at end of list.
|
||||||
* @param vm the LuaState to leave the values on
|
* @param vm the LuaState to leave the values on
|
||||||
|
* @param indexedonly TODO
|
||||||
* @param index index to start search
|
* @param index index to start search
|
||||||
|
* @return true if next exists, false if at end of list
|
||||||
*/
|
*/
|
||||||
public void next(LuaState vm, LValue key ) {
|
public boolean next(LuaState vm, LValue key, boolean indexedonly ) {
|
||||||
|
|
||||||
// find place to start looking
|
int n = (m_vector != null? m_vector.length: 0);
|
||||||
int start = nextKey2StartIndex( vm, key );
|
int i = findindex(key, n, indexedonly);
|
||||||
|
if ( i == INVALID_KEY_TO_NEXT )
|
||||||
|
vm.error( "invalid key to 'next'" );
|
||||||
|
|
||||||
// look in vector part
|
// check vector part
|
||||||
int n = m_vector.length;
|
for ( ++i; i<n; ++i ) {
|
||||||
if ( start < n ) {
|
if ( ! m_vector[i].isNil() ) {
|
||||||
for ( int i=start; i<n; i++ ) {
|
vm.pushinteger(i+1);
|
||||||
if ( m_vector[i] != LNil.NIL ) {
|
vm.pushlvalue(m_vector[i]);
|
||||||
vm.pushinteger(i+1);
|
return true;
|
||||||
vm.pushlvalue(m_vector[i]);
|
} else if ( indexedonly ) {
|
||||||
return;
|
vm.pushnil();
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
start = n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// look in hash part
|
// check hash part
|
||||||
if ( m_hashKeys != null ) {
|
if ( (! indexedonly) && (m_hashKeys != null) ) {
|
||||||
for ( int i=start-n; i<m_hashKeys.length; i++ ) {
|
int m = m_hashKeys.length;
|
||||||
|
for ( i-=n; i<m; ++i ) {
|
||||||
if ( m_hashKeys[i] != null ) {
|
if ( m_hashKeys[i] != null ) {
|
||||||
vm.pushlvalue(m_hashKeys[i]);
|
vm.pushlvalue(m_hashKeys[i]);
|
||||||
vm.pushlvalue(m_hashValues[i]);
|
vm.pushlvalue(m_hashValues[i]);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nothing found, return nil.
|
// nothing found, push nil, return nil.
|
||||||
vm.pushnil();
|
vm.pushnil();
|
||||||
}
|
return false;
|
||||||
|
|
||||||
private int nextKey2StartIndex( LuaState vm, LValue key ) {
|
|
||||||
if ( key == LNil.NIL )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int n = m_vector.length;
|
|
||||||
if ( n > 0 && key.isInteger() ) {
|
|
||||||
final int index = key.toJavaInt() - 1;
|
|
||||||
if ( index >= 0 && index < n ) {
|
|
||||||
if ( m_vector[index] == LNil.NIL )
|
|
||||||
vm.error( "invalid key to 'next'" );
|
|
||||||
return index + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_hashKeys == null )
|
|
||||||
vm.error( "invalid key to 'next'" );
|
|
||||||
|
|
||||||
int slot = findSlot( key );
|
|
||||||
if ( m_hashKeys[slot] == null )
|
|
||||||
vm.error( "invalid key to 'next'" );
|
|
||||||
|
|
||||||
return n + slot + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int findindex (LValue key, int n, boolean indexedonly) {
|
||||||
|
|
||||||
|
// first iteration
|
||||||
|
if ( key.isNil() )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// is `key' inside array part?
|
||||||
|
if ( key.isInteger() ) {
|
||||||
|
int i = key.toJavaInt();
|
||||||
|
if ( (0 < i) && (i <= n) ) {
|
||||||
|
if ( m_vector[i-1] == LNil.NIL )
|
||||||
|
return INVALID_KEY_TO_NEXT;
|
||||||
|
return i-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vector only?
|
||||||
|
if ( indexedonly )
|
||||||
|
return n;
|
||||||
|
|
||||||
|
if ( m_hashKeys == null )
|
||||||
|
return INVALID_KEY_TO_NEXT;
|
||||||
|
|
||||||
|
// find slot
|
||||||
|
int slot = findSlot(key);
|
||||||
|
if ( m_hashKeys[slot] == null )
|
||||||
|
return INVALID_KEY_TO_NEXT;
|
||||||
|
|
||||||
|
return n + slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the given f over all elements of table. For each element, f is
|
* Executes the given f over all elements of table. For each element, f is
|
||||||
@@ -738,35 +719,26 @@ public class LTable extends LValue {
|
|||||||
*
|
*
|
||||||
* @param vm
|
* @param vm
|
||||||
* @param function
|
* @param function
|
||||||
* @param isforeachi is a table.foreachi() call, not a table.foreach() call
|
* @param indexedonly is a table.foreachi() call, not a table.foreach() call
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public LValue foreach(LuaState vm, LFunction function, boolean isforeachi) {
|
public LValue foreach(LuaState vm, LFunction function, boolean indexedonly) {
|
||||||
for ( int i = 0; i < m_vector.length; ++i ) {
|
|
||||||
if ( m_vector[ i ] != LNil.NIL ) {
|
|
||||||
if ( foreachitem( vm, function, LInteger.valueOf(i+1), m_vector[i] ) )
|
|
||||||
return vm.topointer(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (! isforeachi) && m_hashKeys != null ) {
|
|
||||||
for ( int i = 0; i < m_hashKeys.length; ++i ) {
|
|
||||||
if ( m_hashKeys[ i ] != null ) {
|
|
||||||
if ( foreachitem( vm, function, m_hashKeys[i], m_hashValues[i] ) )
|
|
||||||
return vm.topointer(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return LNil.NIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean foreachitem(LuaState vm, LFunction f, LValue key, LValue value) {
|
LValue key = LNil.NIL;
|
||||||
vm.resettop();
|
while ( true ) {
|
||||||
vm.pushlvalue( f );
|
// push function onto stack
|
||||||
vm.pushlvalue( key );
|
vm.resettop();
|
||||||
vm.pushlvalue( value );
|
vm.pushlvalue(function);
|
||||||
vm.call(2, 1);
|
|
||||||
return ! vm.isnil(1);
|
// get next value
|
||||||
|
if ( ! next(vm,key,indexedonly) )
|
||||||
|
return LNil.NIL;
|
||||||
|
key = vm.topointer(2);
|
||||||
|
|
||||||
|
// call function
|
||||||
|
vm.call(2, 1);
|
||||||
|
if ( ! vm.isnil(-1) )
|
||||||
|
return vm.poplvalue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ public class LValue {
|
|||||||
/** Metatable tag for intercepting table sets */
|
/** Metatable tag for intercepting table sets */
|
||||||
public static final LString TM_METATABLE = new LString("__metatable");
|
public static final LString TM_METATABLE = new LString("__metatable");
|
||||||
|
|
||||||
|
/** Metatable tag for setting table mode */
|
||||||
|
public static final LString TM_MODE = new LString("__mode");
|
||||||
|
|
||||||
protected void conversionError(String target) {
|
protected void conversionError(String target) {
|
||||||
throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target );
|
throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target );
|
||||||
}
|
}
|
||||||
@@ -59,6 +62,11 @@ public class LValue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return true if this value is LNil.NIL, false otherwise */
|
||||||
|
public boolean isNil() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// perform a lua call, return true if the call is to a lua function, false
|
// perform a lua call, return true if the call is to a lua function, false
|
||||||
// if it ran to completion.
|
// if it ran to completion.
|
||||||
public boolean luaStackCall(LuaState vm) {
|
public boolean luaStackCall(LuaState vm) {
|
||||||
@@ -124,7 +132,7 @@ public class LValue {
|
|||||||
LTable mt = luaGetMetatable();
|
LTable mt = luaGetMetatable();
|
||||||
if ( mt != null ) {
|
if ( mt != null ) {
|
||||||
LValue event = mt.get( TM_NEWINDEX );
|
LValue event = mt.get( TM_NEWINDEX );
|
||||||
if ( event != null && event != LNil.NIL ) {
|
if ( event != null && ! event.isNil() ) {
|
||||||
event.luaSetTable( vm, table, key, val );
|
event.luaSetTable( vm, table, key, val );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -141,7 +149,7 @@ public class LValue {
|
|||||||
LTable mt = luaGetMetatable();
|
LTable mt = luaGetMetatable();
|
||||||
if ( mt != null ) {
|
if ( mt != null ) {
|
||||||
LValue event = mt.get( TM_INDEX );
|
LValue event = mt.get( TM_INDEX );
|
||||||
if ( event != null && event != LNil.NIL ) {
|
if ( event != null && ! event.isNil() ) {
|
||||||
event.luaGetTable( vm, table, key );
|
event.luaGetTable( vm, table, key );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -184,13 +192,14 @@ public class LValue {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Valid for tables */
|
/** Valid for tables
|
||||||
public void luaSetMetatable(LValue metatable) {
|
* @return TODO*/
|
||||||
|
public LValue luaSetMetatable(LValue metatable) {
|
||||||
throw new LuaErrorException( "bad argument #1 to 'setmetatable' (table expected, got "+metatable.luaGetTypeName()+")");
|
throw new LuaErrorException( "bad argument #1 to 'setmetatable' (table expected, got "+metatable.luaGetTypeName()+")");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Valid for all types: return the int value identifying the type of this value */
|
/** Valid for all types: return the int value identifying the type of this value */
|
||||||
public abstract int luaGetType();
|
abstract public int luaGetType();
|
||||||
|
|
||||||
|
|
||||||
/** Valid for all types: return the type of this value as an LString */
|
/** Valid for all types: return the type of this value as an LString */
|
||||||
@@ -309,4 +318,8 @@ public class LValue {
|
|||||||
return LNil.NIL;
|
return LNil.NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dereference a potentially weak reference, and return the value */
|
||||||
|
public LValue toStrongReference() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/core/org/luaj/vm/LWeakTable.java
Normal file
110
src/core/org/luaj/vm/LWeakTable.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package org.luaj.vm;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
public class LWeakTable extends LTable {
|
||||||
|
|
||||||
|
private static class LWeakValue extends LValue {
|
||||||
|
private WeakReference ref;
|
||||||
|
private LWeakValue(LValue v) {
|
||||||
|
ref = new WeakReference(v);
|
||||||
|
}
|
||||||
|
public LValue toStrongReference() {
|
||||||
|
return (LValue) ref.get();
|
||||||
|
}
|
||||||
|
public LValue value() {
|
||||||
|
LValue v = (LValue) ref.get();
|
||||||
|
return (v!=null? v: LNil.NIL);
|
||||||
|
}
|
||||||
|
public String toJavaString() {
|
||||||
|
return value().toJavaString();
|
||||||
|
}
|
||||||
|
public int luaGetType() {
|
||||||
|
return value().luaGetType();
|
||||||
|
}
|
||||||
|
public boolean isNil() {
|
||||||
|
return value().isNil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void makestrong(LuaState vm) {
|
||||||
|
LValue v = vm.poplvalue();
|
||||||
|
v = v.toStrongReference();
|
||||||
|
vm.pushlvalue(v!=null? v: LNil.NIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct a new LTable with weak-reference keys */
|
||||||
|
public LWeakTable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor */
|
||||||
|
public LWeakTable(LTable copy) {
|
||||||
|
this.m_arrayEntries = copy.m_arrayEntries;
|
||||||
|
this.m_hashEntries = copy.m_hashEntries;
|
||||||
|
if ( copy.m_vector != null ) {
|
||||||
|
int n = copy.m_vector.length;
|
||||||
|
this.m_vector = new LValue[n];
|
||||||
|
for ( int i=0; i<n; i++ ) {
|
||||||
|
this.m_vector[i] = ( copy.m_vector[i] != null?
|
||||||
|
this.m_vector[i] = new LWeakValue(copy.m_vector[i]):
|
||||||
|
LNil.NIL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( copy.m_hashKeys != null ) {
|
||||||
|
int n = copy.m_hashKeys.length;
|
||||||
|
this.m_hashKeys = new LValue[n];
|
||||||
|
this.m_hashValues = new LValue[n];
|
||||||
|
for ( int i=0; i<n; i++ ) {
|
||||||
|
if ( copy.m_hashKeys[i] != null ) {
|
||||||
|
this.m_hashKeys[i] = copy.m_hashKeys[i];
|
||||||
|
this.m_hashValues[i] = new LWeakValue(copy.m_hashValues[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LValue get(int key) {
|
||||||
|
LValue v = super.get(key).toStrongReference();
|
||||||
|
if ( v == null ) {
|
||||||
|
super.remove(key);
|
||||||
|
return LNil.NIL;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LValue get(LValue key) {
|
||||||
|
LValue v = super.get(key).toStrongReference();
|
||||||
|
if ( v == null ) {
|
||||||
|
super.remove(key);
|
||||||
|
return LNil.NIL;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void luaInsertPos(int pos, LValue value) {
|
||||||
|
super.luaInsertPos(pos, new LWeakValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(int key, LValue value) {
|
||||||
|
super.put(key, new LWeakValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(LValue key, LValue val) {
|
||||||
|
super.put(key, new LWeakValue(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String key, LValue value) {
|
||||||
|
super.put(key, new LWeakValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean next(LuaState vm, LValue key, boolean indexedonly) {
|
||||||
|
while ( super.next(vm, key, indexedonly) ) {
|
||||||
|
makestrong(vm);
|
||||||
|
if ( ! vm.isnil(-1) )
|
||||||
|
return true;
|
||||||
|
vm.pop(1);
|
||||||
|
key = vm.poplvalue();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -810,7 +810,7 @@ public class LuaState extends Lua {
|
|||||||
adjustTop( cb + c );
|
adjustTop( cb + c );
|
||||||
|
|
||||||
// test for continuation
|
// test for continuation
|
||||||
if (this.stack[cb] != LNil.NIL ) { // continue?
|
if (!this.stack[cb].isNil() ) { // continue?
|
||||||
this.stack[cb-1] = this.stack[cb]; // save control variable
|
this.stack[cb-1] = this.stack[cb]; // save control variable
|
||||||
} else {
|
} else {
|
||||||
ci.pc++; // skip over jump
|
ci.pc++; // skip over jump
|
||||||
@@ -1463,7 +1463,7 @@ public class LuaState extends Lua {
|
|||||||
* 0 otherwise.
|
* 0 otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isnil(int index) {
|
public boolean isnil(int index) {
|
||||||
return topointer(index) == LNil.NIL;
|
return topointer(index).isNil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1499,7 +1499,7 @@ public class LuaState extends Lua {
|
|||||||
* string convertible to a number, and 0 otherwise.
|
* string convertible to a number, and 0 otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isnumber(int index) {
|
public boolean isnumber(int index) {
|
||||||
return tolnumber(index) != LNil.NIL;
|
return ! tolnumber(index).isNil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1689,7 +1689,7 @@ public class LuaState extends Lua {
|
|||||||
for ( int i=0; i<n; i++ )
|
for ( int i=0; i<n; i++ )
|
||||||
stack[--top] = null;
|
stack[--top] = null;
|
||||||
}
|
}
|
||||||
private LValue poplvalue() {
|
public LValue poplvalue() {
|
||||||
LValue p = stack[--top];
|
LValue p = stack[--top];
|
||||||
stack[top] = null;
|
stack[top] = null;
|
||||||
return p;
|
return p;
|
||||||
@@ -2034,7 +2034,11 @@ public class LuaState extends Lua {
|
|||||||
public void setmetatable(int index) {
|
public void setmetatable(int index) {
|
||||||
LTable t = totable(index);
|
LTable t = totable(index);
|
||||||
LValue v = poplvalue();
|
LValue v = poplvalue();
|
||||||
t.luaSetMetatable(v);
|
LValue n = t.luaSetMetatable(v);
|
||||||
|
if ( n != null ) {
|
||||||
|
pushlvalue(n);
|
||||||
|
replace(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class CoerceLuaToJava {
|
|||||||
return value.toJavaBoolean()? Boolean.TRUE: Boolean.FALSE;
|
return value.toJavaBoolean()? Boolean.TRUE: Boolean.FALSE;
|
||||||
}
|
}
|
||||||
public int score(LValue value) {
|
public int score(LValue value) {
|
||||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
if ( value instanceof LBoolean || value.isNil() )
|
||||||
return 0;
|
return 0;
|
||||||
if ( value instanceof LNumber )
|
if ( value instanceof LNumber )
|
||||||
return 1;
|
return 1;
|
||||||
@@ -66,7 +66,7 @@ public class CoerceLuaToJava {
|
|||||||
return 0;
|
return 0;
|
||||||
if ( value instanceof LNumber )
|
if ( value instanceof LNumber )
|
||||||
return 1;
|
return 1;
|
||||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
if ( value instanceof LBoolean || value.isNil() )
|
||||||
return 2;
|
return 2;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ public class CoerceLuaToJava {
|
|||||||
return 0;
|
return 0;
|
||||||
if ( value instanceof LNumber )
|
if ( value instanceof LNumber )
|
||||||
return 1;
|
return 1;
|
||||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
if ( value instanceof LBoolean || value.isNil() )
|
||||||
return 2;
|
return 2;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ public class CoerceLuaToJava {
|
|||||||
return new Double(value.toJavaDouble());
|
return new Double(value.toJavaDouble());
|
||||||
if ( value instanceof LBoolean )
|
if ( value instanceof LBoolean )
|
||||||
return Boolean.valueOf(value.toJavaBoolean());
|
return Boolean.valueOf(value.toJavaBoolean());
|
||||||
if ( value == LNil.NIL )
|
if ( value.isNil() )
|
||||||
return null;
|
return null;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public class LuaRunner {
|
|||||||
System.err.println(script+" lua error, "+lee.getMessage() );
|
System.err.println(script+" lua error, "+lee.getMessage() );
|
||||||
} catch ( Throwable t ) {
|
} catch ( Throwable t ) {
|
||||||
System.err.println(script+" threw "+t);
|
System.err.println(script+" threw "+t);
|
||||||
|
t.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
|
|||||||
53
src/test/java/org/luaj/vm/LWeakTableTest.java
Normal file
53
src/test/java/org/luaj/vm/LWeakTableTest.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package org.luaj.vm;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class LWeakTableTest extends TestCase {
|
||||||
|
|
||||||
|
Random random = new Random(0);
|
||||||
|
Runtime rt = Runtime.getRuntime();
|
||||||
|
|
||||||
|
private void runTest(int n,int i0,int i1,int di) {
|
||||||
|
System.out.println("------- testing "+n+" keys up to "+i1+" bytes each ("+(n*i1)+" bytes total)");
|
||||||
|
LTable t = new LWeakTable();
|
||||||
|
for ( int i=0; i<n; i++ )
|
||||||
|
t.put(i, new LString(new byte[1]));
|
||||||
|
for ( int i=i0; i<=i1; i+=di ) {
|
||||||
|
int hits = 0;
|
||||||
|
for ( int j=0; j<100; j++ ) {
|
||||||
|
int k = random.nextInt(n);
|
||||||
|
LValue v = t.get(k);
|
||||||
|
if ( v != LNil.NIL )
|
||||||
|
hits++;
|
||||||
|
t.put(i, new LString(new byte[i]));
|
||||||
|
}
|
||||||
|
long total = rt.totalMemory() / 1000;
|
||||||
|
long free = rt.freeMemory() / 1000;
|
||||||
|
long used = (rt.totalMemory() - rt.freeMemory()) / 1000;
|
||||||
|
System.out.println("keys="+n+" bytes="+i+" mem u(f,t)="+used+"("+free+"/"+total+") hits="+hits+"/100");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWeakTable5000() {
|
||||||
|
runTest(100,0,5000,500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWeakTable10000() {
|
||||||
|
runTest(100,0,10000,1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWeakTable100() {
|
||||||
|
runTest(100,0,100,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWeakTable1000() {
|
||||||
|
runTest(100,0,1000,100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWeakTable2000() {
|
||||||
|
runTest(100,0,2000,200);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,69 +18,70 @@ tryconcat( { a='aaa', b='bbb', c='ccc', d='ddd', e='eee' } )
|
|||||||
tryconcat( { [501]="one", [502]="two", [503]="three", [504]="four", [505]="five" } )
|
tryconcat( { [501]="one", [502]="two", [503]="three", [504]="four", [505]="five" } )
|
||||||
tryconcat( {} )
|
tryconcat( {} )
|
||||||
|
|
||||||
|
-- print the elements of a table in a platform-independent way
|
||||||
|
function eles(t,f)
|
||||||
|
f = f or pairs
|
||||||
|
all = {}
|
||||||
|
for k,v in f(t) do
|
||||||
|
table.insert( all, "["..tostring(k).."]="..tostring(v) )
|
||||||
|
end
|
||||||
|
table.sort( all )
|
||||||
|
return "{"..table.concat(all,',').."}"
|
||||||
|
end
|
||||||
|
|
||||||
-- insert, maxn
|
-- insert, maxn
|
||||||
print( '-- insert, maxn tests' )
|
print( '-- insert, maxn tests' )
|
||||||
local t = { "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
local t = { "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
print( eles(t) )
|
||||||
table.insert(t,'six')
|
table.insert(t,'six'); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
table.insert(t,1,'seven'); print( eles(t) )
|
||||||
table.insert(t,1,'seven')
|
table.insert(t,4,'eight'); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
table.insert(t,7,'nine'); print( eles(t) )
|
||||||
table.insert(t,4,'eight')
|
table.insert(t,10,'ten'); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
|
||||||
table.insert(t,7,'nine')
|
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
|
||||||
table.insert(t,10,'ten')
|
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
|
||||||
print( t[10] )
|
|
||||||
print( table.maxn({}), #{} )
|
|
||||||
|
|
||||||
-- remove
|
-- remove
|
||||||
print( '-- remove tests' )
|
print( '-- remove tests' )
|
||||||
t = { "one", "two", "three", "four", "five", "six", "seven", [10]="ten", a='aaa', b='bbb', c='ccc' }
|
t = { "one", "two", "three", "four", "five", "six", "seven", [10]="ten", a='aaa', b='bbb', c='ccc' }
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
print( eles(t) )
|
||||||
print( table.remove(t) )
|
print( 'table.remove(t)', table.remove(t) ); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t) )
|
print( 'table.remove(t,1)', table.remove(t,1) ); print( eles(t) )
|
||||||
print( table.remove(t,1) )
|
print( 'table.remove(t,3)', table.remove(t,3) ); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t) )
|
print( 'table.remove(t,5)', table.remove(t,5) ); print( eles(t) )
|
||||||
print( table.remove(t,3) )
|
print( 'table.remove(t,10)', table.remove(t,10) ); print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t) )
|
print( 'table.remove(t,-1)', table.remove(t,-1) ); print( eles(t) )
|
||||||
print( table.remove(t,5) )
|
print( 'table.remove(t,-1)', table.remove(t,-1) ) ; print( eles(t) )
|
||||||
print( table.concat(t,'-'), table.maxn(t), t[10] )
|
|
||||||
print( table.remove(t,10) )
|
|
||||||
print( table.concat(t,'-'), table.maxn(t), t[10] )
|
|
||||||
print( table.remove(t,-1) )
|
|
||||||
print( table.concat(t,'-'), table.maxn(t), t[10] )
|
|
||||||
print( table.remove(t,-1) )
|
|
||||||
print( table.concat(t,'-'), table.maxn(t), t[10] )
|
|
||||||
|
|
||||||
-- sort
|
-- sort
|
||||||
print( '-- sort tests' )
|
print( '-- sort tests' )
|
||||||
t = { "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
function sorttest(t,f)
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
t = (t)
|
||||||
table.sort(t)
|
print( table.concat(t,'-') )
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
if f then
|
||||||
t = { "zzz", "yyy", "xxx", "www", "vvv", "uuu", "ttt", "sss" }
|
table.sort(t,f)
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
else
|
||||||
table.sort(t)
|
table.sort(t)
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
end
|
||||||
table.sort(t,function(a,b) return b<a end)
|
print( table.concat(t,'-') )
|
||||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
end
|
||||||
|
sorttest{ "one", "two", "three" }
|
||||||
|
sorttest{ "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" }
|
||||||
|
sorttest( { "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" }, function(a,b) return b<a end)
|
||||||
|
|
||||||
-- getn
|
-- getn
|
||||||
t0 = {}
|
t0 = {}
|
||||||
t1 = { 'one', 'two', 'three' }
|
t1 = { 'one', 'two', 'three' }
|
||||||
t2 = { a='aa', b='bb', c='cc' }
|
t2 = { a='aa', b='bb', c='cc' }
|
||||||
t3 = { 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
t3 = { 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
||||||
print( 'getn(t0)', pcall( table.getn, t0 ) )
|
print( 'getn('..eles(t0)..')', pcall( table.getn, t0 ) )
|
||||||
print( 'getn(t0)', pcall( table.getn, t1 ) )
|
print( 'getn('..eles(t1)..')', pcall( table.getn, t1 ) )
|
||||||
print( 'getn(t0)', pcall( table.getn, t2 ) )
|
print( 'getn('..eles(t2)..')', pcall( table.getn, t2 ) )
|
||||||
print( 'getn(t0)', pcall( table.getn, t3 ) )
|
print( 'getn('..eles(t3)..')', pcall( table.getn, t3 ) )
|
||||||
|
|
||||||
-- foreach
|
-- foreach
|
||||||
function test( f, t, result, name )
|
function test( f, t, result, name )
|
||||||
status, value = pcall( f, t, function(...)
|
status, value = pcall( f, t, function(...)
|
||||||
print(name,...)
|
print(' -- ',...)
|
||||||
|
print(' next',next(t,(...)))
|
||||||
return result
|
return result
|
||||||
end )
|
end )
|
||||||
print( name, 's,v', status, value )
|
print( name, 's,v', status, value )
|
||||||
@@ -90,12 +91,32 @@ function testall( f, t, name )
|
|||||||
test( f, t, false, name..'fls' )
|
test( f, t, false, name..'fls' )
|
||||||
test( f, t, 100, name..'100' )
|
test( f, t, 100, name..'100' )
|
||||||
end
|
end
|
||||||
testall( table.foreach, t0, 'table.foreach(t0)' )
|
testall( table.foreach, t0, 'table.foreach('..eles(t0)..')' )
|
||||||
testall( table.foreach, t1, 'table.foreach(t1)' )
|
testall( table.foreach, t1, 'table.foreach('..eles(t1)..')' )
|
||||||
testall( table.foreach, t2, 'table.foreach(t2)' )
|
testall( table.foreach, t2, 'table.foreach('..eles(t2)..')' )
|
||||||
testall( table.foreach, t3, 'table.foreach(t3)' )
|
testall( table.foreach, t3, 'table.foreach('..eles(t3)..')' )
|
||||||
testall( table.foreachi, t0, 'table.foreachi(t0)' )
|
testall( table.foreachi, t0, 'table.foreachi('..eles(t0)..')' )
|
||||||
testall( table.foreachi, t1, 'table.foreachi(t1)' )
|
testall( table.foreachi, t1, 'table.foreachi('..eles(t1)..')' )
|
||||||
testall( table.foreachi, t2, 'table.foreachi(t2)' )
|
testall( table.foreachi, t2, 'table.foreachi('..eles(t2)..')' )
|
||||||
testall( table.foreachi, t3, 'table.foreachi(t3)' )
|
testall( table.foreachi, t3, 'table.foreachi('..eles(t3)..')' )
|
||||||
|
|
||||||
|
-- pairs, ipairs
|
||||||
|
function testpairs(f, t, name)
|
||||||
|
print( name )
|
||||||
|
for a,b in f(t) do
|
||||||
|
print( ' ', a, b )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function testbothpairs(t)
|
||||||
|
testpairs( pairs, t, 'pairs( '..eles(t)..' )' )
|
||||||
|
testpairs( ipairs, t, 'ipairs( '..eles(t)..' )' )
|
||||||
|
end
|
||||||
|
for i,t in ipairs({t0,t1,t2,t3}) do
|
||||||
|
testbothpairs(t)
|
||||||
|
end
|
||||||
|
t = { 'one', 'two', 'three', 'four', 'five' }
|
||||||
|
testbothpairs(t)
|
||||||
|
t[6] = 'six'
|
||||||
|
testbothpairs(t)
|
||||||
|
t[4] = nil
|
||||||
|
testbothpairs(t)
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
-- concat
|
|
||||||
print( '-- weak table tests' )
|
|
||||||
|
|
||||||
-- construct new weak table
|
|
||||||
function newweak(t)
|
function newtable(t)
|
||||||
return setmetatable(t,{__mode="v"})
|
n = setmetatable(t,{__mode="v"})
|
||||||
|
for k,v in pairs(t) do
|
||||||
|
n[k] = v
|
||||||
|
end
|
||||||
|
return n;
|
||||||
end
|
end
|
||||||
|
|
||||||
-- print the elements of a table in a platform-independent way
|
-- normalized printing
|
||||||
function eles(t,f)
|
function eles(t,f)
|
||||||
f = f or pairs
|
f = f or pairs
|
||||||
all = {}
|
all = {}
|
||||||
@@ -14,12 +16,47 @@ function eles(t,f)
|
|||||||
table.insert( all, "["..tostring(k).."]="..tostring(v) )
|
table.insert( all, "["..tostring(k).."]="..tostring(v) )
|
||||||
end
|
end
|
||||||
table.sort( all )
|
table.sort( all )
|
||||||
return "{"..table.concat(all,',').."}"
|
return tostring(t).."{"..table.concat(all,',').."}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- basic weak-reference table test
|
||||||
|
local src = "return { 'one', 'two', 'three', 'four', a='aaa', b='bbb', c='ccc', d='ddd'}"
|
||||||
|
local weak = newtable( loadstring(src)() )
|
||||||
|
local strong = { weak[1], weak[3], a=weak.a, c=weak.c }
|
||||||
|
print( 'before, weak:', eles(weak) )
|
||||||
|
print( 'before, strong:', eles(strong) )
|
||||||
|
print( 'gc', pcall( collectgarbage, "collect" ) )
|
||||||
|
print( 'after, weak:', eles(weak) )
|
||||||
|
print( 'after, strong:', eles(strong) )
|
||||||
|
print( 'gc', pcall( collectgarbage, "collect" ) )
|
||||||
|
print( 'after, weak:', eles(weak) )
|
||||||
|
print( 'after, strong:', eles(strong) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print( '-- concat tests' )
|
||||||
|
function tryconcat(t)
|
||||||
|
print( table.concat(t) )
|
||||||
|
print( table.concat(t,'--') )
|
||||||
|
print( table.concat(t,',',2) )
|
||||||
|
print( table.concat(t,',',2,2) )
|
||||||
|
print( table.concat(t,',',5,2) )
|
||||||
|
end
|
||||||
|
tryconcat( newtable{ "one", "two", "three", a='aaa', b='bbb', c='ccc' } )
|
||||||
|
tryconcat( newtable{ "one", "two", "three", "four", "five" } )
|
||||||
|
function tryconcat(t)
|
||||||
|
print( table.concat(t) )
|
||||||
|
print( table.concat(t,'--') )
|
||||||
|
print( table.concat(t,',',2) )
|
||||||
|
end
|
||||||
|
tryconcat( newtable{ a='aaa', b='bbb', c='ccc', d='ddd', e='eee' } )
|
||||||
|
tryconcat( newtable{ [501]="one", [502]="two", [503]="three", [504]="four", [505]="five" } )
|
||||||
|
tryconcat( newtable{} )
|
||||||
|
|
||||||
-- insert, maxn
|
-- insert, maxn
|
||||||
print( '-- insert, maxn tests' )
|
print( '-- insert, maxn tests' )
|
||||||
local t = newweak{ "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
local t = newtable{ "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
||||||
print( eles(t) )
|
print( eles(t) )
|
||||||
table.insert(t,'six'); print( eles(t) )
|
table.insert(t,'six'); print( eles(t) )
|
||||||
table.insert(t,1,'seven'); print( eles(t) )
|
table.insert(t,1,'seven'); print( eles(t) )
|
||||||
@@ -29,20 +66,20 @@ table.insert(t,10,'ten'); print( eles(t) )
|
|||||||
|
|
||||||
-- remove
|
-- remove
|
||||||
print( '-- remove tests' )
|
print( '-- remove tests' )
|
||||||
t = newweak{ "one", "two", "three", "four", "five", "six", "seven", [10]="ten", a='aaa', b='bbb', c='ccc' }
|
t = newtable{ "one", "two", "three", "four", "five", "six", "seven", [10]="ten", a='aaa', b='bbb', c='ccc' }
|
||||||
print( eles(t) )
|
print( eles(t) )
|
||||||
print( table.remove(t) ); print( eles(t) )
|
print( 'table.remove(t)', table.remove(t) ); print( eles(t) )
|
||||||
print( table.remove(t,1) ); print( eles(t) )
|
print( 'table.remove(t,1)', table.remove(t,1) ); print( eles(t) )
|
||||||
print( table.remove(t,3) ); print( eles(t) )
|
print( 'table.remove(t,3)', table.remove(t,3) ); print( eles(t) )
|
||||||
print( table.remove(t,5) ); print( eles(t) )
|
print( 'table.remove(t,5)', table.remove(t,5) ); print( eles(t) )
|
||||||
print( table.remove(t,10) ); print( eles(t) )
|
print( 'table.remove(t,10)', table.remove(t,10) ); print( eles(t) )
|
||||||
print( table.remove(t,-1) ); print( eles(t) )
|
print( 'table.remove(t,-1)', table.remove(t,-1) ); print( eles(t) )
|
||||||
print( table.remove(t,-1) ) ; print( eles(t) )
|
print( 'table.remove(t,-1)', table.remove(t,-1) ) ; print( eles(t) )
|
||||||
|
|
||||||
-- sort
|
-- sort
|
||||||
print( '-- sort tests' )
|
print( '-- sort tests' )
|
||||||
function sorttest(t,f)
|
function sorttest(t,f)
|
||||||
t = newweak(t)
|
t = (t)
|
||||||
print( table.concat(t,'-') )
|
print( table.concat(t,'-') )
|
||||||
if f then
|
if f then
|
||||||
table.sort(t,f)
|
table.sort(t,f)
|
||||||
@@ -50,25 +87,28 @@ function sorttest(t,f)
|
|||||||
table.sort(t)
|
table.sort(t)
|
||||||
end
|
end
|
||||||
print( table.concat(t,'-') )
|
print( table.concat(t,'-') )
|
||||||
end
|
end
|
||||||
sorttest{ "one", "two", "three" }
|
--[[
|
||||||
sorttest{ "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" }
|
sorttest( newtable{ "one", "two", "three" } )
|
||||||
sorttest( { "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" }, function(a,b) return b<a end)
|
sorttest( newtable{ "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" } )
|
||||||
|
sorttest( newtable{ "www", "vvv", "uuu", "ttt", "sss", "zzz", "yyy", "xxx" }, function(a,b) return b<a end)
|
||||||
|
--]]
|
||||||
|
|
||||||
-- getn
|
-- getn
|
||||||
t0 = newweak{}
|
t0 = newtable{}
|
||||||
t1 = newweak{ 'one', 'two', 'three' }
|
t1 = newtable{ 'one', 'two', 'three' }
|
||||||
t2 = newweak{ a='aa', b='bb', c='cc' }
|
t2 = newtable{ a='aa', b='bb', c='cc' }
|
||||||
t3 = newweak{ 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
t3 = newtable{ 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
||||||
print( 'getn(t0)', pcall( table.getn, t0 ) )
|
print( 'getn('..eles(t0)..')', pcall( table.getn, t0 ) )
|
||||||
print( 'getn(t1)', pcall( table.getn, t1 ) )
|
print( 'getn('..eles(t1)..')', pcall( table.getn, t1 ) )
|
||||||
print( 'getn(t2)', pcall( table.getn, t2 ) )
|
print( 'getn('..eles(t2)..')', pcall( table.getn, t2 ) )
|
||||||
print( 'getn(t3)', pcall( table.getn, t3 ) )
|
print( 'getn('..eles(t3)..')', pcall( table.getn, t3 ) )
|
||||||
|
|
||||||
-- foreach
|
-- foreach
|
||||||
function test( f, t, result, name )
|
function test( f, t, result, name )
|
||||||
status, value = pcall( f, t, function(...)
|
status, value = pcall( f, t, function(...)
|
||||||
print(name,...)
|
print(' -- ',...)
|
||||||
|
print(' next',next(t,(...)))
|
||||||
return result
|
return result
|
||||||
end )
|
end )
|
||||||
print( name, 's,v', status, value )
|
print( name, 's,v', status, value )
|
||||||
@@ -78,29 +118,32 @@ function testall( f, t, name )
|
|||||||
test( f, t, false, name..'fls' )
|
test( f, t, false, name..'fls' )
|
||||||
test( f, t, 100, name..'100' )
|
test( f, t, 100, name..'100' )
|
||||||
end
|
end
|
||||||
testall( table.foreach, t0, 'table.foreach(t0)' )
|
testall( table.foreach, t0, 'table.foreach('..eles(t0)..')' )
|
||||||
testall( table.foreach, t1, 'table.foreach(t1)' )
|
testall( table.foreach, t1, 'table.foreach('..eles(t1)..')' )
|
||||||
testall( table.foreach, t2, 'table.foreach(t2)' )
|
testall( table.foreach, t2, 'table.foreach('..eles(t2)..')' )
|
||||||
testall( table.foreach, t3, 'table.foreach(t3)' )
|
testall( table.foreach, t3, 'table.foreach('..eles(t3)..')' )
|
||||||
testall( table.foreachi, t0, 'table.foreachi(t0)' )
|
testall( table.foreachi, t0, 'table.foreachi('..eles(t0)..')' )
|
||||||
testall( table.foreachi, t1, 'table.foreachi(t1)' )
|
testall( table.foreachi, t1, 'table.foreachi('..eles(t1)..')' )
|
||||||
testall( table.foreachi, t2, 'table.foreachi(t2)' )
|
testall( table.foreachi, t2, 'table.foreachi('..eles(t2)..')' )
|
||||||
testall( table.foreachi, t3, 'table.foreachi(t3)' )
|
testall( table.foreachi, t3, 'table.foreachi('..eles(t3)..')' )
|
||||||
|
|
||||||
-- pairs, ipairs
|
-- pairs, ipairs
|
||||||
function testpairs(f, t, name)
|
function testpairs(f, t, name)
|
||||||
print( name, unpack(t) )
|
print( name )
|
||||||
for a,b in f(t) do
|
for a,b in f(t) do
|
||||||
print( a, b )
|
print( ' ', a, b )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
testpairs( pairs, t0, 'pairs(t0)' )
|
function testbothpairs(t)
|
||||||
testpairs( pairs, t1, 'pairs(t1)' )
|
testpairs( pairs, t, 'pairs( '..eles(t)..' )' )
|
||||||
testpairs( pairs, t2, 'pairs(t2)' )
|
testpairs( ipairs, t, 'ipairs( '..eles(t)..' )' )
|
||||||
testpairs( pairs, t3, 'pairs(t3)' )
|
end
|
||||||
testpairs( ipairs, t0, 'ipairs(t0)' )
|
for i,t in ipairs({t0,t1,t2,t3}) do
|
||||||
testpairs( ipairs, t1, 'ipairs(t1)' )
|
testbothpairs(t)
|
||||||
testpairs( ipairs, t2, 'ipairs(t2)' )
|
end
|
||||||
testpairs( ipairs, t3, 'ipairs(t3)' )
|
t = newtable{ 'one', 'two', 'three', 'four', 'five' }
|
||||||
|
testbothpairs(t)
|
||||||
|
t[6] = 'six'
|
||||||
|
testbothpairs(t)
|
||||||
|
t[4] = nil
|
||||||
|
testbothpairs(t)
|
||||||
|
|||||||
Reference in New Issue
Block a user