Refactor table implementation.
This commit is contained in:
@@ -71,9 +71,10 @@ It also includes miscellaneous improvements over luaj 2.0.x:
|
|||||||
<li>Better coroutine-related garbage collection.
|
<li>Better coroutine-related garbage collection.
|
||||||
<li>Better debug reporting when using closures.
|
<li>Better debug reporting when using closures.
|
||||||
<li>Line numbers in parse syntax tree.
|
<li>Line numbers in parse syntax tree.
|
||||||
|
<li>More compatible table behavior.
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Luaj 2.0.x</h3>
|
<h3>Luaj 2.0.x</h3>
|
||||||
Support for luaj 5.1.x features, plus:
|
Support for lua 5.1.x features, plus:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Support for compiling lua source code into Java source code.
|
<li>Support for compiling lua source code into Java source code.
|
||||||
<li>Support for compiling lua bytecode directly into Java bytecode.
|
<li>Support for compiling lua bytecode directly into Java bytecode.
|
||||||
@@ -82,7 +83,7 @@ Support for luaj 5.1.x features, plus:
|
|||||||
<li>Implementation of weak keys and values, and all metatags.
|
<li>Implementation of weak keys and values, and all metatags.
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Luaj 1.0.x</h3>
|
<h3>Luaj 1.0.x</h3>
|
||||||
Support for most luaj 5.1.x features.
|
Support for most lua 5.1.x features.
|
||||||
|
|
||||||
<h2>Performance</h2>
|
<h2>Performance</h2>
|
||||||
Good performance is a major goal of luaj.
|
Good performance is a major goal of luaj.
|
||||||
@@ -854,6 +855,10 @@ Files are no longer hosted at LuaForge.
|
|||||||
<li>Fix bug in luajava overload resolution.</li>
|
<li>Fix bug in luajava overload resolution.</li>
|
||||||
<li>Fix luastring bug where parsing did not check for overflow.</li>
|
<li>Fix luastring bug where parsing did not check for overflow.</li>
|
||||||
<li>Fix luastring bug where circular dependency randomly caused NullPointerException.</li>
|
<li>Fix luastring bug where circular dependency randomly caused NullPointerException.</li>
|
||||||
|
<li>Major refactor of table implementation.</li>
|
||||||
|
<li>Improved behavior of next() (fixes issue #7).</li>
|
||||||
|
<li>Existing tables can now be made weak (fixes issue #16).</li>
|
||||||
|
<li>More compatible allocation of table entries in array vs. hash (fixes issue #8).</li>
|
||||||
|
|
||||||
</ul></td></tr>
|
</ul></td></tr>
|
||||||
</table></td></tr></table>
|
</table></td></tr></table>
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ public class LuaInteger extends LuaNumber {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int hashCode(int x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
// unary operators
|
// unary operators
|
||||||
public LuaValue neg() { return valueOf(-(long)v); }
|
public LuaValue neg() { return valueOf(-(long)v); }
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -120,7 +120,7 @@ public class LuaUserdata extends LuaValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// __eq metatag processing
|
// __eq metatag processing
|
||||||
public boolean eqmt( LuaValue val ) {
|
public boolean eqmt( LuaValue val ) {
|
||||||
return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
|
return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1384,7 +1384,7 @@ public class LuaValue extends Varargs {
|
|||||||
* @see LuaFunction#s_metatable
|
* @see LuaFunction#s_metatable
|
||||||
* @see LuaThread#s_metatable
|
* @see LuaThread#s_metatable
|
||||||
*/
|
*/
|
||||||
public LuaValue getmetatable() { return null; };
|
public LuaValue getmetatable() { return null; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the metatable for this {@link LuaValue}
|
* Set the metatable for this {@link LuaValue}
|
||||||
@@ -3131,24 +3131,12 @@ public class LuaValue extends Varargs {
|
|||||||
*/
|
*/
|
||||||
public LuaString strvalue() { typerror("strValue"); return null; }
|
public LuaString strvalue() { typerror("strValue"); return null; }
|
||||||
|
|
||||||
/** Return the key part of this value if it is a weak table entry, or {@link NIL} if it was weak and is no longer referenced.
|
/** Return this value as a strong reference, or null if it was weak and is no longer referenced.
|
||||||
* @return {@link LuaValue} key, or {@link NIL} if it was weak and is no longer referenced.
|
* @return {@link LuaValue} referred to, or null if it was weak and is no longer referenced.
|
||||||
* @see WeakTable
|
|
||||||
*/
|
|
||||||
public LuaValue strongkey() { return strongvalue(); }
|
|
||||||
|
|
||||||
/** Return this value as a strong reference, or {@link NIL} if it was weak and is no longer referenced.
|
|
||||||
* @return {@link LuaValue} referred to, or {@link NIL} if it was weak and is no longer referenced.
|
|
||||||
* @see WeakTable
|
* @see WeakTable
|
||||||
*/
|
*/
|
||||||
public LuaValue strongvalue() { return this; }
|
public LuaValue strongvalue() { return this; }
|
||||||
|
|
||||||
/** Test if this is a weak reference and its value no longer is referenced.
|
|
||||||
* @return true if this is a weak reference whose value no longer is referenced
|
|
||||||
* @see WeakTable
|
|
||||||
*/
|
|
||||||
public boolean isweaknil() { return false; }
|
|
||||||
|
|
||||||
/** Convert java boolean to a {@link LuaValue}.
|
/** Convert java boolean to a {@link LuaValue}.
|
||||||
*
|
*
|
||||||
* @param b boolean value to convert
|
* @param b boolean value to convert
|
||||||
@@ -3365,6 +3353,26 @@ public class LuaValue extends Varargs {
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Construct a Metatable instance from the given LuaValue */
|
||||||
|
protected static Metatable metatableOf(LuaValue mt) {
|
||||||
|
if ( mt != null && mt.istable() ) {
|
||||||
|
LuaValue mode = mt.rawget(MODE);
|
||||||
|
if ( mode.isstring() ) {
|
||||||
|
String m = mode.tojstring();
|
||||||
|
boolean weakkeys = m.indexOf('k') >= 0;
|
||||||
|
boolean weakvalues = m.indexOf('v') >= 0;
|
||||||
|
if ( weakkeys || weakvalues ) {
|
||||||
|
return new WeakTable(weakkeys, weakvalues, mt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (LuaTable)mt;
|
||||||
|
} else if ( mt != null ) {
|
||||||
|
return new NonTableMetatable( mt );
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Throw {@link LuaError} indicating index was attempted on illegal type
|
/** Throw {@link LuaError} indicating index was attempted on illegal type
|
||||||
* @throws LuaError when called.
|
* @throws LuaError when called.
|
||||||
*/
|
*/
|
||||||
|
|||||||
51
src/core/org/luaj/vm2/Metatable.java
Normal file
51
src/core/org/luaj/vm2/Metatable.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013 Luaj.org. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
|
package org.luaj.vm2;
|
||||||
|
|
||||||
|
import org.luaj.vm2.LuaTable.Slot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides operations that depend on the __mode key of the metatable.
|
||||||
|
*/
|
||||||
|
interface Metatable {
|
||||||
|
|
||||||
|
/** Return whether or not this table's keys are weak. */
|
||||||
|
public boolean useWeakKeys();
|
||||||
|
|
||||||
|
/** Return whether or not this table's values are weak. */
|
||||||
|
public boolean useWeakValues();
|
||||||
|
|
||||||
|
/** Return this metatable as a LuaValue. */
|
||||||
|
public LuaValue toLuaValue();
|
||||||
|
|
||||||
|
/** Return an instance of Slot appropriate for the given key and value. */
|
||||||
|
public Slot entry( LuaValue key, LuaValue value );
|
||||||
|
|
||||||
|
/** Returns the given value wrapped in a weak reference if appropriate. */
|
||||||
|
public LuaValue wrap( LuaValue value );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value at the given index in the array, or null if it is a weak reference that
|
||||||
|
* has been dropped.
|
||||||
|
*/
|
||||||
|
public LuaValue arrayget(LuaValue[] array, int index);
|
||||||
|
}
|
||||||
36
src/core/org/luaj/vm2/NonTableMetatable.java
Normal file
36
src/core/org/luaj/vm2/NonTableMetatable.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package org.luaj.vm2;
|
||||||
|
|
||||||
|
import org.luaj.vm2.LuaTable.Slot;
|
||||||
|
|
||||||
|
class NonTableMetatable implements Metatable {
|
||||||
|
|
||||||
|
private final LuaValue value;
|
||||||
|
|
||||||
|
public NonTableMetatable(LuaValue value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean useWeakKeys() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean useWeakValues() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue toLuaValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot entry(LuaValue key, LuaValue value) {
|
||||||
|
return LuaTable.defaultEntry(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue wrap(LuaValue value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue arrayget(LuaValue[] array, int index) {
|
||||||
|
return array[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
* Copyright (c) 2009-2011, 2013 Luaj.org. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,7 +23,8 @@ package org.luaj.vm2;
|
|||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
import org.luaj.vm2.lib.TwoArgFunction;
|
import org.luaj.vm2.LuaTable.Slot;
|
||||||
|
import org.luaj.vm2.LuaTable.StrongSlot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
|
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
|
||||||
@@ -34,71 +35,268 @@ import org.luaj.vm2.lib.TwoArgFunction;
|
|||||||
* However, calling the constructors directly when weak tables are required from
|
* However, calling the constructors directly when weak tables are required from
|
||||||
* Java will reduce overhead.
|
* Java will reduce overhead.
|
||||||
*/
|
*/
|
||||||
public class WeakTable extends LuaTable {
|
public class WeakTable implements Metatable {
|
||||||
private boolean weakkeys,weakvalues;
|
|
||||||
|
private boolean weakkeys, weakvalues;
|
||||||
|
private LuaValue backing;
|
||||||
|
|
||||||
|
public static LuaTable make(boolean weakkeys, boolean weakvalues) {
|
||||||
|
LuaString mode;
|
||||||
|
if ( weakkeys && weakvalues ) {
|
||||||
|
mode = LuaString.valueOf("kv");
|
||||||
|
} else if ( weakkeys ) {
|
||||||
|
mode = LuaString.valueOf("k");
|
||||||
|
} else if ( weakvalues ) {
|
||||||
|
mode = LuaString.valueOf("v");
|
||||||
|
} else {
|
||||||
|
return LuaTable.tableOf();
|
||||||
|
}
|
||||||
|
LuaTable table = LuaTable.tableOf();
|
||||||
|
LuaTable mt = LuaTable.tableOf(new LuaValue[] { LuaValue.MODE, mode });
|
||||||
|
table.setmetatable(mt);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a table with weak keys, weak values, or both
|
* Construct a table with weak keys, weak values, or both
|
||||||
* @param weakkeys true to let the table have weak keys
|
* @param weakkeys true to let the table have weak keys
|
||||||
* @param weakvalues true to let the table have weak values
|
* @param weakvalues true to let the table have weak values
|
||||||
*/
|
*/
|
||||||
public WeakTable(boolean weakkeys, boolean weakvalues) {
|
public WeakTable(boolean weakkeys, boolean weakvalues, LuaValue backing) {
|
||||||
this(weakkeys, weakvalues, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a table with weak keys, weak values, or both, and an initial capacity
|
|
||||||
* @param weakkeys true to let the table have weak keys
|
|
||||||
* @param weakvalues true to let the table have weak values
|
|
||||||
* @param narray capacity of array part
|
|
||||||
* @param nhash capacity of hash part
|
|
||||||
*/
|
|
||||||
protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) {
|
|
||||||
super(narray, nhash);
|
|
||||||
this.weakkeys = weakkeys;
|
this.weakkeys = weakkeys;
|
||||||
this.weakvalues = weakvalues;
|
this.weakvalues = weakvalues;
|
||||||
|
this.backing = backing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean useWeakKeys() {
|
||||||
* Construct a table with weak keys, weak values, or both, and a source of initial data
|
return weakkeys;
|
||||||
* @param weakkeys true to let the table have weak keys
|
|
||||||
* @param weakvalues true to let the table have weak values
|
|
||||||
* @param source {@link LuaTable} containing the initial elements
|
|
||||||
*/
|
|
||||||
protected WeakTable(boolean weakkeys, boolean weakvalues, LuaTable source) {
|
|
||||||
this(weakkeys, weakvalues, source.getArrayLength(), source.getHashLength());
|
|
||||||
Varargs n;
|
|
||||||
LuaValue k = NIL;
|
|
||||||
while ( !(k = ((n = source.next(k)).arg1())).isnil() )
|
|
||||||
rawset(k, n.arg(2));
|
|
||||||
m_metatable = source.m_metatable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void presize( int narray ) {
|
public boolean useWeakValues() {
|
||||||
super.presize(narray);
|
return weakvalues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public LuaValue toLuaValue() {
|
||||||
* Presize capacity of both array and hash parts.
|
return backing;
|
||||||
* @param narray capacity of array part
|
|
||||||
* @param nhash capacity of hash part
|
|
||||||
*/
|
|
||||||
public void presize(int narray, int nhash) {
|
|
||||||
super.presize(narray, nhash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getArrayLength() {
|
public Slot entry(LuaValue key, LuaValue value) {
|
||||||
return super.getArrayLength();
|
value = value.strongvalue();
|
||||||
|
if ( value == null )
|
||||||
|
return null;
|
||||||
|
if ( weakkeys && !( key.isnumber() || key.isstring() || key.isboolean() )) {
|
||||||
|
if ( weakvalues && !( value.isnumber() || value.isstring() || value.isboolean() )) {
|
||||||
|
return new WeakKeyAndValueSlot( key, value, null );
|
||||||
|
} else {
|
||||||
|
return new WeakKeySlot( key, value, null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( weakvalues && ! (value.isnumber() || value.isstring() || value.isboolean() )) {
|
||||||
|
return new WeakValueSlot( key, value, null );
|
||||||
|
}
|
||||||
|
return LuaTable.defaultEntry( key, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getHashLength() {
|
public static abstract class WeakSlot implements Slot {
|
||||||
return super.getHashLength();
|
|
||||||
|
protected Object key;
|
||||||
|
protected Object value;
|
||||||
|
protected Slot next;
|
||||||
|
|
||||||
|
protected WeakSlot(Object key, Object value, Slot next) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int keyindex( int hashMask );
|
||||||
|
|
||||||
|
public abstract Slot set(LuaValue value);
|
||||||
|
|
||||||
|
public StrongSlot first() {
|
||||||
|
LuaValue key = strongkey();
|
||||||
|
LuaValue value = strongvalue();
|
||||||
|
if ( key != null && value != null ) {
|
||||||
|
return new LuaTable.NormalEntry(key, value);
|
||||||
|
} else {
|
||||||
|
this.key = null;
|
||||||
|
this.value = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StrongSlot find(LuaValue key) {
|
||||||
|
StrongSlot first = first();
|
||||||
|
return ( first != null ) ? first.find( key ) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyeq(LuaValue key) {
|
||||||
|
StrongSlot first = first();
|
||||||
|
return ( first != null ) && first.keyeq( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot rest() {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int arraykey(int max) {
|
||||||
|
// Integer keys can never be weak.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot set(StrongSlot target, LuaValue value) {
|
||||||
|
LuaValue key = strongkey();
|
||||||
|
if ( key != null && target.find( key ) != null ) {
|
||||||
|
return set( value );
|
||||||
|
} else if ( key != null ) {
|
||||||
|
// Our key is still good.
|
||||||
|
next = next.set( target, value );
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
// our key was dropped, remove ourselves from the chain.
|
||||||
|
return next.set( target, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot add( Slot entry ) {
|
||||||
|
next = ( next != null ) ? next.add( entry ) : entry;
|
||||||
|
if ( strongkey() != null && strongvalue() != null ) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot remove( StrongSlot target ) {
|
||||||
|
LuaValue key = strongkey();
|
||||||
|
if ( key == null ) {
|
||||||
|
return next.remove( target );
|
||||||
|
} else if ( target.keyeq( key ) ) {
|
||||||
|
this.value = null;
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
next = next.remove( target );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot relink( Slot rest ) {
|
||||||
|
if ( strongkey() != null && strongvalue() != null ) {
|
||||||
|
if ( rest == null && this.next == null ) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
return copy( rest );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongkey() {
|
||||||
|
return (LuaValue) key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongvalue() {
|
||||||
|
return (LuaValue) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract WeakSlot copy( Slot next );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
|
static class WeakKeySlot extends WeakSlot {
|
||||||
this.weakkeys = weakkeys;
|
|
||||||
this.weakvalues = weakvalues;
|
private final int keyhash;
|
||||||
return this;
|
|
||||||
|
protected WeakKeySlot( LuaValue key, LuaValue value, Slot next ) {
|
||||||
|
super(weaken(key), value, next);
|
||||||
|
keyhash = key.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakKeySlot( WeakKeySlot copyFrom, Slot next ) {
|
||||||
|
super( copyFrom.key, copyFrom.value, next );
|
||||||
|
this.keyhash = copyFrom.keyhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int keyindex( int mask ) {
|
||||||
|
return LuaTable.hashmod( keyhash, mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot set(LuaValue value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongkey() {
|
||||||
|
return strengthen( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakSlot copy( Slot rest ) {
|
||||||
|
return new WeakKeySlot( this, rest );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WeakValueSlot extends WeakSlot {
|
||||||
|
|
||||||
|
protected WeakValueSlot( LuaValue key, LuaValue value, Slot next ) {
|
||||||
|
super( key, weaken(value), next);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakValueSlot( WeakValueSlot copyFrom, Slot next ) {
|
||||||
|
super( copyFrom.key, copyFrom.value, next );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int keyindex( int mask ) {
|
||||||
|
return LuaTable.hashSlot( strongkey(), mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot set(LuaValue value) {
|
||||||
|
this.value = weaken(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongvalue() {
|
||||||
|
return strengthen( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakSlot copy(Slot next) {
|
||||||
|
return new WeakValueSlot( this, next );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WeakKeyAndValueSlot extends WeakSlot {
|
||||||
|
|
||||||
|
private final int keyhash;
|
||||||
|
|
||||||
|
protected WeakKeyAndValueSlot( LuaValue key, LuaValue value, Slot next ) {
|
||||||
|
super( weaken(key), weaken(value), next );
|
||||||
|
keyhash = key.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakKeyAndValueSlot(WeakKeyAndValueSlot copyFrom, Slot next) {
|
||||||
|
super( copyFrom.key, copyFrom.value, next );
|
||||||
|
keyhash = copyFrom.keyhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int keyindex( int hashMask ) {
|
||||||
|
return LuaTable.hashmod( keyhash, hashMask );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot set(LuaValue value) {
|
||||||
|
this.value = weaken(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongkey() {
|
||||||
|
return strengthen( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue strongvalue() {
|
||||||
|
return strengthen( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WeakSlot copy( Slot next ) {
|
||||||
|
return new WeakKeyAndValueSlot( this, next );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +304,7 @@ public class WeakTable extends LuaTable {
|
|||||||
* @param value value to convert
|
* @param value value to convert
|
||||||
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
|
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
|
||||||
*/
|
*/
|
||||||
LuaValue weaken( LuaValue value ) {
|
protected static LuaValue weaken( LuaValue value ) {
|
||||||
switch ( value.type() ) {
|
switch ( value.type() ) {
|
||||||
case LuaValue.TFUNCTION:
|
case LuaValue.TFUNCTION:
|
||||||
case LuaValue.TTHREAD:
|
case LuaValue.TTHREAD:
|
||||||
@@ -119,107 +317,27 @@ public class WeakTable extends LuaTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rawset( int key, LuaValue value ) {
|
|
||||||
if ( weakvalues )
|
|
||||||
value = weaken( value );
|
|
||||||
super.rawset(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rawset( LuaValue key, LuaValue value ) {
|
|
||||||
if ( weakvalues )
|
|
||||||
value = weaken( value );
|
|
||||||
if ( weakkeys ) {
|
|
||||||
switch ( key.type() ) {
|
|
||||||
case LuaValue.TFUNCTION:
|
|
||||||
case LuaValue.TTHREAD:
|
|
||||||
case LuaValue.TTABLE:
|
|
||||||
case LuaValue.TUSERDATA:
|
|
||||||
key = value = new WeakEntry(this, key, value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.rawset(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public LuaValue rawget( int key ) {
|
|
||||||
return super.rawget(key).strongvalue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LuaValue rawget( LuaValue key ) {
|
|
||||||
return super.rawget(key).strongvalue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the hash value for a key
|
|
||||||
* key the key to look up
|
|
||||||
* */
|
|
||||||
protected LuaValue hashget(LuaValue key) {
|
|
||||||
if ( hashEntries > 0 ) {
|
|
||||||
int i = hashFindSlot(key);
|
|
||||||
if ( hashEntries == 0 )
|
|
||||||
return NIL;
|
|
||||||
LuaValue v = hashValues[i];
|
|
||||||
return v!=null? v: NIL;
|
|
||||||
}
|
|
||||||
return NIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// override to remove values for weak keys as we search
|
|
||||||
public int hashFindSlot(LuaValue key) {
|
|
||||||
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
|
|
||||||
LuaValue k;
|
|
||||||
while ( ( k = hashKeys[i] ) != null ) {
|
|
||||||
if ( k.isweaknil() ) {
|
|
||||||
hashClearSlot(i);
|
|
||||||
if ( hashEntries == 0 )
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( k.raweq(key.strongkey()) )
|
|
||||||
return i;
|
|
||||||
i = ( i + 1 ) % hashKeys.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next element after a particular key in the table
|
* Unwrap a LuaValue from a WeakReference and/or WeakUserdata.
|
||||||
* @return key,value or nil
|
* @param ref reference to convert
|
||||||
|
* @return LuaValue or null
|
||||||
|
* @see #weaken(LuaValue)
|
||||||
*/
|
*/
|
||||||
public Varargs next( LuaValue key ) {
|
protected static LuaValue strengthen(Object ref) {
|
||||||
while ( true ) {
|
if ( ref instanceof WeakReference ) {
|
||||||
Varargs n = super.next(key);
|
ref = ((WeakReference) ref).get();
|
||||||
LuaValue k = n.arg1();
|
|
||||||
if ( k.isnil() )
|
|
||||||
return NIL;
|
|
||||||
LuaValue ks = k.strongkey();
|
|
||||||
LuaValue vs = n.arg(2).strongvalue();
|
|
||||||
if ( ks.isnil() || vs.isnil() ) {
|
|
||||||
super.rawset(k, NIL);
|
|
||||||
} else {
|
|
||||||
return varargsOf(ks,vs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if ( ref instanceof WeakValue ) {
|
||||||
|
return ((WeakValue) ref).strongvalue();
|
||||||
// ----------------- sort support -----------------------------
|
}
|
||||||
public void sort(final LuaValue comparator) {
|
return (LuaValue) ref;
|
||||||
super.sort( new TwoArgFunction() {
|
|
||||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
|
||||||
return comparator.call( arg1.strongvalue(), arg2.strongvalue() );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Internal class to implement weak values.
|
/** Internal class to implement weak values.
|
||||||
* @see WeakTable
|
* @see WeakTable
|
||||||
*/
|
*/
|
||||||
static class WeakValue extends LuaValue {
|
static class WeakValue extends LuaValue {
|
||||||
final WeakReference ref;
|
WeakReference ref;
|
||||||
|
|
||||||
protected WeakValue(LuaValue value) {
|
protected WeakValue(LuaValue value) {
|
||||||
ref = new WeakReference(value);
|
ref = new WeakReference(value);
|
||||||
@@ -241,17 +359,13 @@ public class WeakTable extends LuaTable {
|
|||||||
|
|
||||||
public LuaValue strongvalue() {
|
public LuaValue strongvalue() {
|
||||||
Object o = ref.get();
|
Object o = ref.get();
|
||||||
return o!=null? (LuaValue)o: NIL;
|
return (LuaValue)o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean raweq(LuaValue rhs) {
|
public boolean raweq(LuaValue rhs) {
|
||||||
Object o = ref.get();
|
Object o = ref.get();
|
||||||
return o!=null && rhs.raweq((LuaValue)o);
|
return o!=null && rhs.raweq((LuaValue)o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isweaknil() {
|
|
||||||
return ref.get() == null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Internal class to implement weak userdata values.
|
/** Internal class to implement weak userdata values.
|
||||||
@@ -272,73 +386,28 @@ public class WeakTable extends LuaTable {
|
|||||||
if ( u != null )
|
if ( u != null )
|
||||||
return (LuaValue) u;
|
return (LuaValue) u;
|
||||||
Object o = ob.get();
|
Object o = ob.get();
|
||||||
return o!=null? userdataOf(o,mt): NIL;
|
if ( o != null ) {
|
||||||
}
|
LuaValue ud = LuaValue.userdataOf(o,mt);
|
||||||
|
ref = new WeakReference(ud);
|
||||||
public boolean raweq(LuaValue rhs) {
|
return ud;
|
||||||
if ( ! rhs.isuserdata() )
|
} else {
|
||||||
return false;
|
return null;
|
||||||
LuaValue v = (LuaValue) ref.get();
|
}
|
||||||
if ( v != null && v.raweq(rhs) )
|
|
||||||
return true;
|
|
||||||
return rhs.touserdata() == ob.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isweaknil() {
|
|
||||||
return ob.get() == null || ref.get() == null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Internal class to implement weak table entries.
|
public LuaValue wrap(LuaValue value) {
|
||||||
* @see WeakTable
|
return weakvalues ? weaken( value ) : value;
|
||||||
*/
|
}
|
||||||
static final class WeakEntry extends LuaValue {
|
|
||||||
final LuaValue weakkey;
|
|
||||||
LuaValue weakvalue;
|
|
||||||
final int keyhash;
|
|
||||||
|
|
||||||
private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) {
|
public LuaValue arrayget(LuaValue[] array, int index) {
|
||||||
this.weakkey = table.weaken(key);
|
LuaValue value = array[index];
|
||||||
this.keyhash = key.hashCode();
|
if (value != null) {
|
||||||
this.weakvalue = weakvalue;
|
value = strengthen(value);
|
||||||
}
|
if (value == null) {
|
||||||
|
array[index] = null;
|
||||||
public LuaValue strongkey() {
|
}
|
||||||
return weakkey.strongvalue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// when looking up the value, look in the keys metatable
|
|
||||||
public LuaValue strongvalue() {
|
|
||||||
LuaValue key = weakkey.strongvalue();
|
|
||||||
if ( key.isnil() )
|
|
||||||
return weakvalue = NIL;
|
|
||||||
return weakvalue.strongvalue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int type() {
|
|
||||||
return TNONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String typename() {
|
|
||||||
illegal("typename","weak entry");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "weak<"+weakkey.strongvalue()+","+strongvalue()+">";
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return keyhash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean raweq(LuaValue rhs) {
|
|
||||||
//return rhs.raweq(weakkey.strongvalue());
|
|
||||||
return weakkey.raweq(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isweaknil() {
|
|
||||||
return weakkey.isweaknil() || weakvalue.isweaknil();
|
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class TableHashTest extends TestCase {
|
|||||||
|
|
||||||
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01",
|
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01",
|
||||||
"cd", "ef", "g", "hi", "jk", "lm", "no", "pq", "rs", };
|
"cd", "ef", "g", "hi", "jk", "lm", "no", "pq", "rs", };
|
||||||
int[] capacities = { 0, 2, 4, 4, 7, 7, 7, 10, 10, 14, 14, 14, 14, 19, 19, 19, 19, 25, 25, 25 };
|
int[] capacities = { 0, 2, 2, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32 };
|
||||||
for ( int i = 0; i < keys.length; ++i ) {
|
for ( int i = 0; i < keys.length; ++i ) {
|
||||||
assertEquals( capacities[i], t.getHashLength() );
|
assertEquals( capacities[i], t.getHashLength() );
|
||||||
String si = "Test Value! "+i;
|
String si = "Test Value! "+i;
|
||||||
@@ -242,4 +242,79 @@ public class TableHashTest extends TestCase {
|
|||||||
assertEquals( LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2) );
|
assertEquals( LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2) );
|
||||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("bb")) );
|
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("bb")) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLoopWithRemoval() {
|
||||||
|
final LuaTable t = new_Table();
|
||||||
|
|
||||||
|
t.set( LuaValue.valueOf(1), LuaValue.valueOf("1") );
|
||||||
|
t.set( LuaValue.valueOf(3), LuaValue.valueOf("3") );
|
||||||
|
t.set( LuaValue.valueOf(8), LuaValue.valueOf("4") );
|
||||||
|
t.set( LuaValue.valueOf(17), LuaValue.valueOf("5") );
|
||||||
|
t.set( LuaValue.valueOf(26), LuaValue.valueOf("6") );
|
||||||
|
t.set( LuaValue.valueOf(35), LuaValue.valueOf("7") );
|
||||||
|
t.set( LuaValue.valueOf(42), LuaValue.valueOf("8") );
|
||||||
|
t.set( LuaValue.valueOf(60), LuaValue.valueOf("10") );
|
||||||
|
t.set( LuaValue.valueOf(63), LuaValue.valueOf("11") );
|
||||||
|
|
||||||
|
Varargs entry = t.next(LuaValue.NIL);
|
||||||
|
while ( !entry.isnil(1) ) {
|
||||||
|
LuaValue k = entry.arg1();
|
||||||
|
LuaValue v = entry.arg(2);
|
||||||
|
if ( ( k.toint() & 1 ) == 0 ) {
|
||||||
|
t.set( k, LuaValue.NIL );
|
||||||
|
}
|
||||||
|
entry = t.next(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numEntries = 0;
|
||||||
|
entry = t.next(LuaValue.NIL);
|
||||||
|
while ( !entry.isnil(1) ) {
|
||||||
|
LuaValue k = entry.arg1();
|
||||||
|
// Only odd keys should remain
|
||||||
|
assertTrue( ( k.toint() & 1 ) == 1 );
|
||||||
|
numEntries++;
|
||||||
|
entry = t.next(k);
|
||||||
|
}
|
||||||
|
assertEquals( 5, numEntries );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLoopWithRemovalAndSet() {
|
||||||
|
final LuaTable t = new_Table();
|
||||||
|
|
||||||
|
t.set( LuaValue.valueOf(1), LuaValue.valueOf("1") );
|
||||||
|
t.set( LuaValue.valueOf(3), LuaValue.valueOf("3") );
|
||||||
|
t.set( LuaValue.valueOf(8), LuaValue.valueOf("4") );
|
||||||
|
t.set( LuaValue.valueOf(17), LuaValue.valueOf("5") );
|
||||||
|
t.set( LuaValue.valueOf(26), LuaValue.valueOf("6") );
|
||||||
|
t.set( LuaValue.valueOf(35), LuaValue.valueOf("7") );
|
||||||
|
t.set( LuaValue.valueOf(42), LuaValue.valueOf("8") );
|
||||||
|
t.set( LuaValue.valueOf(60), LuaValue.valueOf("10") );
|
||||||
|
t.set( LuaValue.valueOf(63), LuaValue.valueOf("11") );
|
||||||
|
|
||||||
|
Varargs entry = t.next(LuaValue.NIL);
|
||||||
|
Varargs entry2 = entry;
|
||||||
|
while ( !entry.isnil(1) ) {
|
||||||
|
LuaValue k = entry.arg1();
|
||||||
|
LuaValue v = entry.arg(2);
|
||||||
|
if ( ( k.toint() & 1 ) == 0 ) {
|
||||||
|
t.set( k, LuaValue.NIL );
|
||||||
|
} else {
|
||||||
|
t.set( k, v.tonumber() );
|
||||||
|
entry2 = t.next(entry2.arg1());
|
||||||
|
}
|
||||||
|
entry = t.next(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numEntries = 0;
|
||||||
|
entry = t.next(LuaValue.NIL);
|
||||||
|
while ( !entry.isnil(1) ) {
|
||||||
|
LuaValue k = entry.arg1();
|
||||||
|
// Only odd keys should remain
|
||||||
|
assertTrue( ( k.toint() & 1 ) == 1 );
|
||||||
|
assertTrue( entry.arg(2).type() == LuaValue.TNUMBER );
|
||||||
|
numEntries++;
|
||||||
|
entry = t.next(k);
|
||||||
|
}
|
||||||
|
assertEquals( 5, numEntries );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,8 +88,9 @@ public class TableTest extends TestCase {
|
|||||||
assertEquals(LuaInteger.valueOf(i), t.get(i));
|
assertEquals(LuaInteger.valueOf(i), t.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue( t.getArrayLength() >= 0 && t.getArrayLength() <= 2 );
|
assertTrue( t.getArrayLength() >= 3 );
|
||||||
assertTrue( t.getHashLength() >= 4 );
|
assertTrue( t.getArrayLength() <= 12 );
|
||||||
|
assertTrue( t.getHashLength() <= 3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOutOfOrderIntegerKeyInsertion() {
|
public void testOutOfOrderIntegerKeyInsertion() {
|
||||||
@@ -105,12 +106,8 @@ public class TableTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure capacities make sense
|
// Ensure capacities make sense
|
||||||
assertTrue( t.getArrayLength() >= 0 );
|
assertEquals( 32, t.getArrayLength() );
|
||||||
assertTrue( t.getArrayLength() <= 6 );
|
assertEquals( 0, t.getHashLength() );
|
||||||
|
|
||||||
assertTrue( t.getHashLength() >= 16 );
|
|
||||||
assertTrue( t.getHashLength() <= 64 );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testStringAndIntegerKeys() {
|
public void testStringAndIntegerKeys() {
|
||||||
@@ -122,8 +119,8 @@ public class TableTest extends TestCase {
|
|||||||
t.set( str, LuaInteger.valueOf( i ) );
|
t.set( str, LuaInteger.valueOf( i ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue( t.getArrayLength() >= 9 ); // 1, 2, ..., 9
|
assertTrue( t.getArrayLength() >= 8 ); // 1, 2, ..., 9
|
||||||
assertTrue( t.getArrayLength() <= 18 );
|
assertTrue( t.getArrayLength() <= 16 );
|
||||||
assertTrue( t.getHashLength() >= 11 ); // 0, "0", "1", ..., "9"
|
assertTrue( t.getHashLength() >= 11 ); // 0, "0", "1", ..., "9"
|
||||||
assertTrue( t.getHashLength() <= 33 );
|
assertTrue( t.getHashLength() <= 33 );
|
||||||
|
|
||||||
@@ -222,6 +219,41 @@ public class TableTest extends TestCase {
|
|||||||
assertEquals( 0, keyCount(t) );
|
assertEquals( 0, keyCount(t) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testShrinkNonPowerOfTwoArray() {
|
||||||
|
LuaTable t = new_Table(6, 2);
|
||||||
|
|
||||||
|
t.set(1, "one");
|
||||||
|
t.set(2, "two");
|
||||||
|
t.set(3, "three");
|
||||||
|
t.set(4, "four");
|
||||||
|
t.set(5, "five");
|
||||||
|
t.set(6, "six");
|
||||||
|
|
||||||
|
t.set("aa", "aaa");
|
||||||
|
t.set("bb", "bbb");
|
||||||
|
|
||||||
|
t.set(3, LuaValue.NIL);
|
||||||
|
t.set(4, LuaValue.NIL);
|
||||||
|
t.set(6, LuaValue.NIL);
|
||||||
|
|
||||||
|
t.set("cc", "ccc");
|
||||||
|
t.set("dd", "ddd");
|
||||||
|
|
||||||
|
assertEquals(4, t.getArrayLength());
|
||||||
|
assertTrue(t.getHashLength() < 10);
|
||||||
|
assertEquals(5, t.hashEntries);
|
||||||
|
assertEquals("one", t.get(1).tojstring());
|
||||||
|
assertEquals("two", t.get(2).tojstring());
|
||||||
|
assertEquals(LuaValue.NIL, t.get(3));
|
||||||
|
assertEquals(LuaValue.NIL, t.get(4));
|
||||||
|
assertEquals("five", t.get(5).tojstring());
|
||||||
|
assertEquals(LuaValue.NIL, t.get(6));
|
||||||
|
assertEquals("aaa", t.get("aa").tojstring());
|
||||||
|
assertEquals("bbb", t.get("bb").tojstring());
|
||||||
|
assertEquals("ccc", t.get("cc").tojstring());
|
||||||
|
assertEquals("ddd", t.get("dd").tojstring());
|
||||||
|
}
|
||||||
|
|
||||||
public void testInOrderLuaLength() {
|
public void testInOrderLuaLength() {
|
||||||
LuaTable t = new_Table();
|
LuaTable t = new_Table();
|
||||||
|
|
||||||
@@ -350,5 +382,4 @@ public class TableTest extends TestCase {
|
|||||||
compareLists(t,v);
|
compareLists(t,v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class WeakValueTableTest extends WeakTableTest {
|
public static class WeakValueTableTest extends WeakTableTest {
|
||||||
protected LuaTable new_Table() { return new WeakTable(false, true); }
|
protected LuaTable new_Table() { return WeakTable.make(false, true); }
|
||||||
protected LuaTable new_Table(int n,int m) { return new WeakTable(false, true); }
|
protected LuaTable new_Table(int n,int m) { return WeakTable.make(false, true); }
|
||||||
|
|
||||||
public void testWeakValuesTable() {
|
public void testWeakValuesTable() {
|
||||||
LuaTable t = new_Table();
|
LuaTable t = new_Table();
|
||||||
@@ -64,17 +64,21 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
LuaTable tableValue = new LuaTable();
|
LuaTable tableValue = new LuaTable();
|
||||||
LuaString stringValue = LuaString.valueOf("this is a test");
|
LuaString stringValue = LuaString.valueOf("this is a test");
|
||||||
|
LuaTable tableValue2 = new LuaTable();
|
||||||
|
|
||||||
t.set("table", tableValue);
|
t.set("table", tableValue);
|
||||||
t.set("userdata", LuaValue.userdataOf(obj, null));
|
t.set("userdata", LuaValue.userdataOf(obj, null));
|
||||||
t.set("string", stringValue);
|
t.set("string", stringValue);
|
||||||
t.set("string2", LuaString.valueOf("another string"));
|
t.set("string2", LuaValue.valueOf("another string"));
|
||||||
assertTrue("table must have at least 4 elements", t.getHashLength() > 4);
|
t.set(1, tableValue2);
|
||||||
|
assertTrue("table must have at least 4 elements", t.getHashLength() >= 4);
|
||||||
|
assertTrue("array part must have 1 element", t.getArrayLength() >= 1);
|
||||||
|
|
||||||
// check that table can be used to get elements
|
// check that table can be used to get elements
|
||||||
assertEquals(tableValue, t.get("table"));
|
assertEquals(tableValue, t.get("table"));
|
||||||
assertEquals(stringValue, t.get("string"));
|
assertEquals(stringValue, t.get("string"));
|
||||||
assertEquals(obj, t.get("userdata").checkuserdata());
|
assertEquals(obj, t.get("userdata").checkuserdata());
|
||||||
|
assertEquals(tableValue2, t.get(1));
|
||||||
|
|
||||||
// nothing should be collected, since we have strong references here
|
// nothing should be collected, since we have strong references here
|
||||||
collectGarbage();
|
collectGarbage();
|
||||||
@@ -83,10 +87,12 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
assertEquals(tableValue, t.get("table"));
|
assertEquals(tableValue, t.get("table"));
|
||||||
assertEquals(stringValue, t.get("string"));
|
assertEquals(stringValue, t.get("string"));
|
||||||
assertEquals(obj, t.get("userdata").checkuserdata());
|
assertEquals(obj, t.get("userdata").checkuserdata());
|
||||||
|
assertEquals(tableValue2, t.get(1));
|
||||||
|
|
||||||
// drop our strong references
|
// drop our strong references
|
||||||
obj = null;
|
obj = null;
|
||||||
tableValue = null;
|
tableValue = null;
|
||||||
|
tableValue2 = null;
|
||||||
stringValue = null;
|
stringValue = null;
|
||||||
|
|
||||||
// Garbage collection should cause weak entries to be dropped.
|
// Garbage collection should cause weak entries to be dropped.
|
||||||
@@ -95,16 +101,17 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
// check that they are dropped
|
// check that they are dropped
|
||||||
assertEquals(LuaValue.NIL, t.get("table"));
|
assertEquals(LuaValue.NIL, t.get("table"));
|
||||||
assertEquals(LuaValue.NIL, t.get("userdata"));
|
assertEquals(LuaValue.NIL, t.get("userdata"));
|
||||||
|
assertEquals(LuaValue.NIL, t.get(1));
|
||||||
assertFalse("strings should not be in weak references", t.get("string").isnil());
|
assertFalse("strings should not be in weak references", t.get("string").isnil());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WeakKeyTableTest extends WeakTableTest {
|
public static class WeakKeyTableTest extends WeakTableTest {
|
||||||
protected LuaTable new_Table() { return new WeakTable(true, false); }
|
protected LuaTable new_Table() { return WeakTable.make(true, false); }
|
||||||
protected LuaTable new_Table(int n,int m) { return new WeakTable(true, false); }
|
protected LuaTable new_Table(int n,int m) { return WeakTable.make(true, false); }
|
||||||
|
|
||||||
public void testWeakKeysTable() {
|
public void testWeakKeysTable() {
|
||||||
LuaTable t = new WeakTable(true, false);
|
LuaTable t = WeakTable.make(true, false);
|
||||||
|
|
||||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||||
@@ -137,7 +144,7 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testNext() {
|
public void testNext() {
|
||||||
LuaTable t = new WeakTable(true, true);
|
LuaTable t = WeakTable.make(true, true);
|
||||||
|
|
||||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||||
@@ -167,11 +174,11 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class WeakKeyValueTableTest extends WeakTableTest {
|
public static class WeakKeyValueTableTest extends WeakTableTest {
|
||||||
protected LuaTable new_Table() { return new WeakTable(true, true); }
|
protected LuaTable new_Table() { return WeakTable.make(true, true); }
|
||||||
protected LuaTable new_Table(int n,int m) { return new WeakTable(true, true); }
|
protected LuaTable new_Table(int n,int m) { return WeakTable.make(true, true); }
|
||||||
|
|
||||||
public void testWeakKeysValuesTable() {
|
public void testWeakKeysValuesTable() {
|
||||||
LuaTable t = new WeakTable(true, true);
|
LuaTable t = WeakTable.make(true, true);
|
||||||
|
|
||||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||||
@@ -224,7 +231,7 @@ abstract public class WeakTableTest extends TableTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testReplace() {
|
public void testReplace() {
|
||||||
LuaTable t = new WeakTable(true, true);
|
LuaTable t = WeakTable.make(true, true);
|
||||||
|
|
||||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||||
|
|||||||
Reference in New Issue
Block a user