Weak table implementation.
This commit is contained in:
@@ -119,7 +119,7 @@ public class DumpState {
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
final LValue o = f.k[i];
|
||||
if (o == LNil.NIL) {
|
||||
if (o.isNil()) {
|
||||
writer.write(Lua.LUA_TNIL);
|
||||
// do nothing more
|
||||
} else if (o instanceof LBoolean) {
|
||||
|
||||
@@ -55,6 +55,7 @@ public class BaseLib extends LFunction {
|
||||
"tostring",
|
||||
"unpack",
|
||||
"next",
|
||||
"_inext", // not public
|
||||
};
|
||||
|
||||
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 UNPACK = 22;
|
||||
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) {
|
||||
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) );
|
||||
next = new BaseLib(NEXT);
|
||||
inext = new BaseLib(INEXT);
|
||||
globals.put("_VERSION", new LString("Lua 5.1"));
|
||||
}
|
||||
|
||||
@@ -142,13 +149,23 @@ public class BaseLib extends LFunction {
|
||||
vm.resettop();
|
||||
break;
|
||||
}
|
||||
case PAIRS:
|
||||
case IPAIRS: {
|
||||
case IPAIRS:
|
||||
case PAIRS: {
|
||||
checkargtype(vm,2,Lua.LUA_TTABLE);
|
||||
LTable v = vm.totable(2);
|
||||
LValue r = v.luaPairs(id==PAIRS);
|
||||
LTable t = vm.totable(2);
|
||||
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;
|
||||
}
|
||||
case GETMETATABLE: {
|
||||
@@ -358,14 +375,6 @@ public class BaseLib extends LFunction {
|
||||
vm.pushlvalue(list.get(k));
|
||||
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:
|
||||
LuaState.vmerror( "bad base id" );
|
||||
}
|
||||
@@ -472,7 +481,7 @@ public class BaseLib extends LFunction {
|
||||
return false;
|
||||
}
|
||||
LValue v = vm.topointer(2);
|
||||
if ( v == LNil.NIL )
|
||||
if ( v.isNil() )
|
||||
break;
|
||||
LString s = v.luaAsString();
|
||||
s.write(baos, 0, s.length());
|
||||
|
||||
@@ -229,7 +229,7 @@ public class PackageLib extends LFunction {
|
||||
e = fname.m_length;
|
||||
LString key = fname.substring(b, e);
|
||||
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 */
|
||||
table.put(key, field);
|
||||
table = field;
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.luaj.vm.LFunction;
|
||||
import org.luaj.vm.LString;
|
||||
import org.luaj.vm.LTable;
|
||||
import org.luaj.vm.LValue;
|
||||
import org.luaj.vm.LWeakTable;
|
||||
import org.luaj.vm.LuaState;
|
||||
|
||||
|
||||
@@ -205,7 +206,7 @@ public class TableLib extends LFunction {
|
||||
vm.resettop();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
LuaState.vmerror( "bad table id" );
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ public final class LNil extends LValue {
|
||||
return luaGetTypeName();
|
||||
}
|
||||
|
||||
public boolean isNil() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean toJavaBoolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,33 +57,35 @@ public class LTable extends LValue {
|
||||
* 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.
|
||||
*/
|
||||
private LValue[] m_hashKeys;
|
||||
protected LValue[] m_hashKeys;
|
||||
|
||||
/**
|
||||
* Values in the hash part. Must be null when m_hashKeys is null and equal
|
||||
* 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
|
||||
* 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
|
||||
* entries with positive integer keys. Elements must never be null: "empty"
|
||||
* slots are set to LNil.NIL.
|
||||
*/
|
||||
private LValue[] m_vector;
|
||||
protected LValue[] m_vector;
|
||||
|
||||
/**
|
||||
* Number of values in m_vector that non-nil.
|
||||
*/
|
||||
private int m_arrayEntries;
|
||||
protected int m_arrayEntries;
|
||||
|
||||
private LTable m_metatable;
|
||||
|
||||
private static final int INVALID_KEY_TO_NEXT = -2;
|
||||
|
||||
/** Construct an empty LTable with no initial capacity. */
|
||||
public LTable() {
|
||||
@@ -123,7 +125,7 @@ public class LTable extends LValue {
|
||||
if ( key.isInteger() ) {
|
||||
// call the integer-specific put method
|
||||
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
|
||||
// for an integer key so that values are properly removed from
|
||||
// the array part.
|
||||
@@ -159,7 +161,7 @@ public class LTable extends LValue {
|
||||
* any.
|
||||
*/
|
||||
public void put( int key, LValue value ) {
|
||||
if (value == null || value == LNil.NIL) {
|
||||
if (value == null || value.isNil()) {
|
||||
remove( key );
|
||||
return;
|
||||
}
|
||||
@@ -167,7 +169,7 @@ public class LTable extends LValue {
|
||||
final int index = key - 1;
|
||||
for ( ;; ) {
|
||||
if ( index < m_vector.length ) {
|
||||
if ( m_vector[index] == LNil.NIL ) {
|
||||
if ( m_vector[index].isNil() ) {
|
||||
++m_arrayEntries;
|
||||
}
|
||||
m_vector[index] = value;
|
||||
@@ -231,8 +233,7 @@ public class LTable extends LValue {
|
||||
if ( m_vector.length > 0 && key.isInteger() ) {
|
||||
final int index = key.toJavaInt() - 1;
|
||||
if ( index >= 0 && index < m_vector.length ) {
|
||||
final LValue v = m_vector[index];
|
||||
return v != LNil.NIL;
|
||||
return ! m_vector[index].isNil();
|
||||
}
|
||||
}
|
||||
if ( m_hashKeys == null )
|
||||
@@ -243,7 +244,7 @@ public class LTable extends LValue {
|
||||
|
||||
public void luaGetTable(LuaState vm, LValue table, LValue key) {
|
||||
LValue v = get(key);
|
||||
if ( v == LNil.NIL && m_metatable != null ) {
|
||||
if ( v.isNil() && m_metatable != null ) {
|
||||
super.luaGetTable( vm, table, key );
|
||||
} else {
|
||||
vm.pushlvalue(v);
|
||||
@@ -264,8 +265,8 @@ public class LTable extends LValue {
|
||||
*/
|
||||
public int luaLength() {
|
||||
for ( int i = Math.max( 0, m_arrayEntries-1 ); i < m_vector.length; ++i ) {
|
||||
if ( m_vector[i] != LNil.NIL &&
|
||||
( i+1 == m_vector.length || m_vector[i+1] == LNil.NIL ) ) {
|
||||
if ( ! m_vector[i].isNil() &&
|
||||
( i+1 == m_vector.length || m_vector[i+1].isNil() ) ) {
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
@@ -278,15 +279,24 @@ public class LTable extends LValue {
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public void luaSetMetatable(LValue metatable) {
|
||||
if ( m_metatable != null && m_metatable.containsKey(TM_METATABLE) )
|
||||
public LValue luaSetMetatable(LValue metatable) {
|
||||
if ( m_metatable != null && m_metatable.containsKey(TM_METATABLE) )
|
||||
throw new LuaErrorException("cannot change a protected metatable");
|
||||
if ( metatable == null || metatable == LNil.NIL )
|
||||
if ( metatable == null || metatable.isNil() )
|
||||
this.m_metatable = null;
|
||||
else if ( metatable.luaGetType() == Lua.LUA_TTABLE )
|
||||
this.m_metatable = (LTable) metatable;
|
||||
else if ( metatable.luaGetType() == Lua.LUA_TTABLE ) {
|
||||
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
|
||||
throw new LuaErrorException("nil or table expected, got "+metatable.luaGetTypeName());
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toJavaString() {
|
||||
@@ -296,47 +306,6 @@ public class LTable extends LValue {
|
||||
public int luaGetType() {
|
||||
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
|
||||
@@ -349,7 +318,7 @@ public class LTable extends LValue {
|
||||
int out = 0;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
@@ -365,11 +334,11 @@ public class LTable extends LValue {
|
||||
}
|
||||
|
||||
/** Remove the value in the table with the given integer key. */
|
||||
private void remove( int key ) {
|
||||
protected void remove( int key ) {
|
||||
if ( key > 0 ) {
|
||||
final int index = key - 1;
|
||||
if ( index < m_vector.length ) {
|
||||
if ( m_vector[ index ] != LNil.NIL ) {
|
||||
if ( ! m_vector[ index ].isNil() ) {
|
||||
m_vector[ index ] = LNil.NIL;
|
||||
--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 ) {
|
||||
int slot = findSlot( key );
|
||||
clearSlot( slot );
|
||||
@@ -522,7 +491,7 @@ public class LTable extends LValue {
|
||||
} else {
|
||||
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
||||
LValue v = m_vector[i];
|
||||
if ( v != LNil.NIL ) {
|
||||
if ( ! v.isNil() ) {
|
||||
if (checkLoadFactor())
|
||||
rehash();
|
||||
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);
|
||||
if ( m_arrayEntries + 1 > m_vector.length )
|
||||
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);
|
||||
}
|
||||
m_vector[index] = value;
|
||||
@@ -572,7 +541,7 @@ public class LTable extends LValue {
|
||||
public LValue luaRemovePos(int pos) {
|
||||
if ( pos > m_arrayEntries ) {
|
||||
LValue val = get( pos );
|
||||
if ( val != LNil.NIL )
|
||||
if ( ! val.isNil() )
|
||||
put( pos, LNil.NIL );
|
||||
return val;
|
||||
} else {
|
||||
@@ -592,7 +561,7 @@ public class LTable extends LValue {
|
||||
LValue result = LInteger.valueOf(0);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@@ -648,7 +617,7 @@ public class LTable extends LValue {
|
||||
}
|
||||
|
||||
private boolean compare(int i, int j, LuaState vm, LValue cmpfunc) {
|
||||
if ( cmpfunc != LNil.NIL ) {
|
||||
if ( ! cmpfunc.isNil() ) {
|
||||
vm.pushlvalue(cmpfunc);
|
||||
vm.pushlvalue(m_vector[i]);
|
||||
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.
|
||||
* @param vm the LuaState to leave the values on
|
||||
* @param indexedonly TODO
|
||||
* @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 start = nextKey2StartIndex( vm, key );
|
||||
int n = (m_vector != null? m_vector.length: 0);
|
||||
int i = findindex(key, n, indexedonly);
|
||||
if ( i == INVALID_KEY_TO_NEXT )
|
||||
vm.error( "invalid key to 'next'" );
|
||||
|
||||
// look in vector part
|
||||
int n = m_vector.length;
|
||||
if ( start < n ) {
|
||||
for ( int i=start; i<n; i++ ) {
|
||||
if ( m_vector[i] != LNil.NIL ) {
|
||||
vm.pushinteger(i+1);
|
||||
vm.pushlvalue(m_vector[i]);
|
||||
return;
|
||||
}
|
||||
// check vector part
|
||||
for ( ++i; i<n; ++i ) {
|
||||
if ( ! m_vector[i].isNil() ) {
|
||||
vm.pushinteger(i+1);
|
||||
vm.pushlvalue(m_vector[i]);
|
||||
return true;
|
||||
} else if ( indexedonly ) {
|
||||
vm.pushnil();
|
||||
return false;
|
||||
}
|
||||
start = n;
|
||||
}
|
||||
|
||||
// look in hash part
|
||||
if ( m_hashKeys != null ) {
|
||||
for ( int i=start-n; i<m_hashKeys.length; i++ ) {
|
||||
// check hash part
|
||||
if ( (! indexedonly) && (m_hashKeys != null) ) {
|
||||
int m = m_hashKeys.length;
|
||||
for ( i-=n; i<m; ++i ) {
|
||||
if ( m_hashKeys[i] != null ) {
|
||||
vm.pushlvalue(m_hashKeys[i]);
|
||||
vm.pushlvalue(m_hashValues[i]);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nothing found, return nil.
|
||||
// nothing found, push nil, return nil.
|
||||
vm.pushnil();
|
||||
}
|
||||
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -738,35 +719,26 @@ public class LTable extends LValue {
|
||||
*
|
||||
* @param vm
|
||||
* @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
|
||||
*/
|
||||
public LValue foreach(LuaState vm, LFunction function, boolean isforeachi) {
|
||||
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;
|
||||
}
|
||||
public LValue foreach(LuaState vm, LFunction function, boolean indexedonly) {
|
||||
|
||||
private static boolean foreachitem(LuaState vm, LFunction f, LValue key, LValue value) {
|
||||
vm.resettop();
|
||||
vm.pushlvalue( f );
|
||||
vm.pushlvalue( key );
|
||||
vm.pushlvalue( value );
|
||||
vm.call(2, 1);
|
||||
return ! vm.isnil(1);
|
||||
LValue key = LNil.NIL;
|
||||
while ( true ) {
|
||||
// push function onto stack
|
||||
vm.resettop();
|
||||
vm.pushlvalue(function);
|
||||
|
||||
// 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 */
|
||||
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) {
|
||||
throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target );
|
||||
}
|
||||
@@ -59,6 +62,11 @@ public class LValue {
|
||||
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
|
||||
// if it ran to completion.
|
||||
public boolean luaStackCall(LuaState vm) {
|
||||
@@ -124,7 +132,7 @@ public class LValue {
|
||||
LTable mt = luaGetMetatable();
|
||||
if ( mt != null ) {
|
||||
LValue event = mt.get( TM_NEWINDEX );
|
||||
if ( event != null && event != LNil.NIL ) {
|
||||
if ( event != null && ! event.isNil() ) {
|
||||
event.luaSetTable( vm, table, key, val );
|
||||
return;
|
||||
}
|
||||
@@ -141,7 +149,7 @@ public class LValue {
|
||||
LTable mt = luaGetMetatable();
|
||||
if ( mt != null ) {
|
||||
LValue event = mt.get( TM_INDEX );
|
||||
if ( event != null && event != LNil.NIL ) {
|
||||
if ( event != null && ! event.isNil() ) {
|
||||
event.luaGetTable( vm, table, key );
|
||||
return;
|
||||
}
|
||||
@@ -184,13 +192,14 @@ public class LValue {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public void luaSetMetatable(LValue metatable) {
|
||||
/** Valid for tables
|
||||
* @return TODO*/
|
||||
public LValue luaSetMetatable(LValue metatable) {
|
||||
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 */
|
||||
public abstract int luaGetType();
|
||||
abstract public int luaGetType();
|
||||
|
||||
|
||||
/** Valid for all types: return the type of this value as an LString */
|
||||
@@ -309,4 +318,8 @@ public class LValue {
|
||||
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 );
|
||||
|
||||
// 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
|
||||
} else {
|
||||
ci.pc++; // skip over jump
|
||||
@@ -1463,7 +1463,7 @@ public class LuaState extends Lua {
|
||||
* 0 otherwise.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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++ )
|
||||
stack[--top] = null;
|
||||
}
|
||||
private LValue poplvalue() {
|
||||
public LValue poplvalue() {
|
||||
LValue p = stack[--top];
|
||||
stack[top] = null;
|
||||
return p;
|
||||
@@ -2034,7 +2034,11 @@ public class LuaState extends Lua {
|
||||
public void setmetatable(int index) {
|
||||
LTable t = totable(index);
|
||||
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;
|
||||
}
|
||||
public int score(LValue value) {
|
||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
||||
if ( value instanceof LBoolean || value.isNil() )
|
||||
return 0;
|
||||
if ( value instanceof LNumber )
|
||||
return 1;
|
||||
@@ -66,7 +66,7 @@ public class CoerceLuaToJava {
|
||||
return 0;
|
||||
if ( value instanceof LNumber )
|
||||
return 1;
|
||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
||||
if ( value instanceof LBoolean || value.isNil() )
|
||||
return 2;
|
||||
return 4;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class CoerceLuaToJava {
|
||||
return 0;
|
||||
if ( value instanceof LNumber )
|
||||
return 1;
|
||||
if ( value instanceof LBoolean || value == LNil.NIL )
|
||||
if ( value instanceof LBoolean || value.isNil() )
|
||||
return 2;
|
||||
return 4;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class CoerceLuaToJava {
|
||||
return new Double(value.toJavaDouble());
|
||||
if ( value instanceof LBoolean )
|
||||
return Boolean.valueOf(value.toJavaBoolean());
|
||||
if ( value == LNil.NIL )
|
||||
if ( value.isNil() )
|
||||
return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public class LuaRunner {
|
||||
System.err.println(script+" lua error, "+lee.getMessage() );
|
||||
} catch ( Throwable t ) {
|
||||
System.err.println(script+" threw "+t);
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
System.out.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( {} )
|
||||
|
||||
-- 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
|
||||
print( '-- insert, maxn tests' )
|
||||
local t = { "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
||||
table.insert(t,'six')
|
||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
||||
table.insert(t,1,'seven')
|
||||
print( table.concat(t,'-'), table.maxn(t), #t, table.getn(t) )
|
||||
table.insert(t,4,'eight')
|
||||
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({}), #{} )
|
||||
print( eles(t) )
|
||||
table.insert(t,'six'); print( eles(t) )
|
||||
table.insert(t,1,'seven'); print( eles(t) )
|
||||
table.insert(t,4,'eight'); print( eles(t) )
|
||||
table.insert(t,7,'nine'); print( eles(t) )
|
||||
table.insert(t,10,'ten'); print( eles(t) )
|
||||
|
||||
-- remove
|
||||
print( '-- remove tests' )
|
||||
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( table.remove(t) )
|
||||
print( table.concat(t,'-'), table.maxn(t) )
|
||||
print( table.remove(t,1) )
|
||||
print( table.concat(t,'-'), table.maxn(t) )
|
||||
print( table.remove(t,3) )
|
||||
print( table.concat(t,'-'), table.maxn(t) )
|
||||
print( table.remove(t,5) )
|
||||
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] )
|
||||
print( eles(t) )
|
||||
print( 'table.remove(t)', table.remove(t) ); print( eles(t) )
|
||||
print( 'table.remove(t,1)', table.remove(t,1) ); print( eles(t) )
|
||||
print( 'table.remove(t,3)', table.remove(t,3) ); print( eles(t) )
|
||||
print( 'table.remove(t,5)', table.remove(t,5) ); print( eles(t) )
|
||||
print( 'table.remove(t,10)', table.remove(t,10) ); print( eles(t) )
|
||||
print( 'table.remove(t,-1)', table.remove(t,-1) ); print( eles(t) )
|
||||
print( 'table.remove(t,-1)', table.remove(t,-1) ) ; print( eles(t) )
|
||||
|
||||
-- sort
|
||||
print( '-- sort tests' )
|
||||
t = { "one", "two", "three", a='aaa', b='bbb', c='ccc' }
|
||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
||||
table.sort(t)
|
||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
||||
t = { "zzz", "yyy", "xxx", "www", "vvv", "uuu", "ttt", "sss" }
|
||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
||||
table.sort(t)
|
||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
||||
table.sort(t,function(a,b) return b<a end)
|
||||
print( table.concat(t,'-'), table.maxn(t), #t )
|
||||
function sorttest(t,f)
|
||||
t = (t)
|
||||
print( table.concat(t,'-') )
|
||||
if f then
|
||||
table.sort(t,f)
|
||||
else
|
||||
table.sort(t)
|
||||
end
|
||||
print( table.concat(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
|
||||
t0 = {}
|
||||
t1 = { 'one', 'two', 'three' }
|
||||
t2 = { 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(t0)', pcall( table.getn, t1 ) )
|
||||
print( 'getn(t0)', pcall( table.getn, t2 ) )
|
||||
print( 'getn(t0)', pcall( table.getn, t3 ) )
|
||||
print( 'getn('..eles(t0)..')', pcall( table.getn, t0 ) )
|
||||
print( 'getn('..eles(t1)..')', pcall( table.getn, t1 ) )
|
||||
print( 'getn('..eles(t2)..')', pcall( table.getn, t2 ) )
|
||||
print( 'getn('..eles(t3)..')', pcall( table.getn, t3 ) )
|
||||
|
||||
-- foreach
|
||||
function test( f, t, result, name )
|
||||
status, value = pcall( f, t, function(...)
|
||||
print(name,...)
|
||||
print(' -- ',...)
|
||||
print(' next',next(t,(...)))
|
||||
return result
|
||||
end )
|
||||
print( name, 's,v', status, value )
|
||||
@@ -90,12 +91,32 @@ function testall( f, t, name )
|
||||
test( f, t, false, name..'fls' )
|
||||
test( f, t, 100, name..'100' )
|
||||
end
|
||||
testall( table.foreach, t0, 'table.foreach(t0)' )
|
||||
testall( table.foreach, t1, 'table.foreach(t1)' )
|
||||
testall( table.foreach, t2, 'table.foreach(t2)' )
|
||||
testall( table.foreach, t3, 'table.foreach(t3)' )
|
||||
testall( table.foreachi, t0, 'table.foreachi(t0)' )
|
||||
testall( table.foreachi, t1, 'table.foreachi(t1)' )
|
||||
testall( table.foreachi, t2, 'table.foreachi(t2)' )
|
||||
testall( table.foreachi, t3, 'table.foreachi(t3)' )
|
||||
testall( table.foreach, t0, 'table.foreach('..eles(t0)..')' )
|
||||
testall( table.foreach, t1, 'table.foreach('..eles(t1)..')' )
|
||||
testall( table.foreach, t2, 'table.foreach('..eles(t2)..')' )
|
||||
testall( table.foreach, t3, 'table.foreach('..eles(t3)..')' )
|
||||
testall( table.foreachi, t0, 'table.foreachi('..eles(t0)..')' )
|
||||
testall( table.foreachi, t1, 'table.foreachi('..eles(t1)..')' )
|
||||
testall( table.foreachi, t2, 'table.foreachi('..eles(t2)..')' )
|
||||
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)
|
||||
return setmetatable(t,{__mode="v"})
|
||||
|
||||
function newtable(t)
|
||||
n = setmetatable(t,{__mode="v"})
|
||||
for k,v in pairs(t) do
|
||||
n[k] = v
|
||||
end
|
||||
return n;
|
||||
end
|
||||
|
||||
-- print the elements of a table in a platform-independent way
|
||||
-- normalized printing
|
||||
function eles(t,f)
|
||||
f = f or pairs
|
||||
all = {}
|
||||
@@ -14,12 +16,47 @@ function eles(t,f)
|
||||
table.insert( all, "["..tostring(k).."]="..tostring(v) )
|
||||
end
|
||||
table.sort( all )
|
||||
return "{"..table.concat(all,',').."}"
|
||||
return tostring(t).."{"..table.concat(all,',').."}"
|
||||
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
|
||||
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) )
|
||||
table.insert(t,'six'); print( eles(t) )
|
||||
table.insert(t,1,'seven'); print( eles(t) )
|
||||
@@ -29,20 +66,20 @@ table.insert(t,10,'ten'); print( eles(t) )
|
||||
|
||||
-- remove
|
||||
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( table.remove(t) ); print( eles(t) )
|
||||
print( table.remove(t,1) ); print( eles(t) )
|
||||
print( table.remove(t,3) ); print( eles(t) )
|
||||
print( table.remove(t,5) ); print( eles(t) )
|
||||
print( table.remove(t,10) ); print( eles(t) )
|
||||
print( table.remove(t,-1) ); print( eles(t) )
|
||||
print( table.remove(t,-1) ) ; print( eles(t) )
|
||||
print( 'table.remove(t)', table.remove(t) ); print( eles(t) )
|
||||
print( 'table.remove(t,1)', table.remove(t,1) ); print( eles(t) )
|
||||
print( 'table.remove(t,3)', table.remove(t,3) ); print( eles(t) )
|
||||
print( 'table.remove(t,5)', table.remove(t,5) ); print( eles(t) )
|
||||
print( 'table.remove(t,10)', table.remove(t,10) ); print( eles(t) )
|
||||
print( 'table.remove(t,-1)', table.remove(t,-1) ); print( eles(t) )
|
||||
print( 'table.remove(t,-1)', table.remove(t,-1) ) ; print( eles(t) )
|
||||
|
||||
-- sort
|
||||
print( '-- sort tests' )
|
||||
function sorttest(t,f)
|
||||
t = newweak(t)
|
||||
t = (t)
|
||||
print( table.concat(t,'-') )
|
||||
if f then
|
||||
table.sort(t,f)
|
||||
@@ -50,25 +87,28 @@ function sorttest(t,f)
|
||||
table.sort(t)
|
||||
end
|
||||
print( table.concat(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)
|
||||
end
|
||||
--[[
|
||||
sorttest( newtable{ "one", "two", "three" } )
|
||||
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
|
||||
t0 = newweak{}
|
||||
t1 = newweak{ 'one', 'two', 'three' }
|
||||
t2 = newweak{ a='aa', b='bb', c='cc' }
|
||||
t3 = newweak{ 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
||||
print( 'getn(t0)', pcall( table.getn, t0 ) )
|
||||
print( 'getn(t1)', pcall( table.getn, t1 ) )
|
||||
print( 'getn(t2)', pcall( table.getn, t2 ) )
|
||||
print( 'getn(t3)', pcall( table.getn, t3 ) )
|
||||
t0 = newtable{}
|
||||
t1 = newtable{ 'one', 'two', 'three' }
|
||||
t2 = newtable{ a='aa', b='bb', c='cc' }
|
||||
t3 = newtable{ 'one', 'two', 'three', a='aa', b='bb', c='cc' }
|
||||
print( 'getn('..eles(t0)..')', pcall( table.getn, t0 ) )
|
||||
print( 'getn('..eles(t1)..')', pcall( table.getn, t1 ) )
|
||||
print( 'getn('..eles(t2)..')', pcall( table.getn, t2 ) )
|
||||
print( 'getn('..eles(t3)..')', pcall( table.getn, t3 ) )
|
||||
|
||||
-- foreach
|
||||
function test( f, t, result, name )
|
||||
status, value = pcall( f, t, function(...)
|
||||
print(name,...)
|
||||
print(' -- ',...)
|
||||
print(' next',next(t,(...)))
|
||||
return result
|
||||
end )
|
||||
print( name, 's,v', status, value )
|
||||
@@ -78,29 +118,32 @@ function testall( f, t, name )
|
||||
test( f, t, false, name..'fls' )
|
||||
test( f, t, 100, name..'100' )
|
||||
end
|
||||
testall( table.foreach, t0, 'table.foreach(t0)' )
|
||||
testall( table.foreach, t1, 'table.foreach(t1)' )
|
||||
testall( table.foreach, t2, 'table.foreach(t2)' )
|
||||
testall( table.foreach, t3, 'table.foreach(t3)' )
|
||||
testall( table.foreachi, t0, 'table.foreachi(t0)' )
|
||||
testall( table.foreachi, t1, 'table.foreachi(t1)' )
|
||||
testall( table.foreachi, t2, 'table.foreachi(t2)' )
|
||||
testall( table.foreachi, t3, 'table.foreachi(t3)' )
|
||||
testall( table.foreach, t0, 'table.foreach('..eles(t0)..')' )
|
||||
testall( table.foreach, t1, 'table.foreach('..eles(t1)..')' )
|
||||
testall( table.foreach, t2, 'table.foreach('..eles(t2)..')' )
|
||||
testall( table.foreach, t3, 'table.foreach('..eles(t3)..')' )
|
||||
testall( table.foreachi, t0, 'table.foreachi('..eles(t0)..')' )
|
||||
testall( table.foreachi, t1, 'table.foreachi('..eles(t1)..')' )
|
||||
testall( table.foreachi, t2, 'table.foreachi('..eles(t2)..')' )
|
||||
testall( table.foreachi, t3, 'table.foreachi('..eles(t3)..')' )
|
||||
|
||||
-- pairs, ipairs
|
||||
function testpairs(f, t, name)
|
||||
print( name, unpack(t) )
|
||||
print( name )
|
||||
for a,b in f(t) do
|
||||
print( a, b )
|
||||
print( ' ', a, b )
|
||||
end
|
||||
end
|
||||
testpairs( pairs, t0, 'pairs(t0)' )
|
||||
testpairs( pairs, t1, 'pairs(t1)' )
|
||||
testpairs( pairs, t2, 'pairs(t2)' )
|
||||
testpairs( pairs, t3, 'pairs(t3)' )
|
||||
testpairs( ipairs, t0, 'ipairs(t0)' )
|
||||
testpairs( ipairs, t1, 'ipairs(t1)' )
|
||||
testpairs( ipairs, t2, 'ipairs(t2)' )
|
||||
testpairs( ipairs, t3, 'ipairs(t3)' )
|
||||
|
||||
|
||||
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 = 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