Simplify weak table implementation.

This commit is contained in:
James Roseborough
2010-07-05 18:30:04 +00:00
parent 514765fa74
commit 700d3878a0
3 changed files with 59 additions and 42 deletions

View File

@@ -444,7 +444,7 @@ public class LuaTable extends LuaValue {
} }
} }
private void hashClearSlot( int i ) { protected void hashClearSlot( int i ) {
if ( hashKeys[ i ] != null ) { if ( hashKeys[ i ] != null ) {
int j = i; int j = i;

View File

@@ -26,14 +26,13 @@ import java.lang.ref.WeakReference;
import org.luaj.vm2.lib.TwoArgFunction; import org.luaj.vm2.lib.TwoArgFunction;
public class WeakTable extends LuaTable { public class WeakTable extends LuaTable {
private LuaTable backing;
private boolean weakkeys,weakvalues; private boolean weakkeys,weakvalues;
public WeakTable(boolean weakkeys, boolean weakvalues) { public WeakTable(boolean weakkeys, boolean weakvalues) {
this(weakkeys, weakvalues, 0, 0); this(weakkeys, weakvalues, 0, 0);
} }
protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) { protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) {
this.backing = new LuaTable(narray, nhash); super(narray, nhash);
this.weakkeys = weakkeys; this.weakkeys = weakkeys;
this.weakvalues = weakvalues; this.weakvalues = weakvalues;
} }
@@ -47,19 +46,19 @@ public class WeakTable extends LuaTable {
} }
public void presize( int narray ) { public void presize( int narray ) {
backing.presize(narray); super.presize(narray);
} }
public void presize(int narray, int nhash) { public void presize(int narray, int nhash) {
backing.presize(narray, nhash); super.presize(narray, nhash);
} }
protected int getArrayLength() { protected int getArrayLength() {
return backing.getArrayLength(); return super.getArrayLength();
} }
protected int getHashLength() { protected int getHashLength() {
return backing.getHashLength(); return super.getHashLength();
} }
protected WeakTable changemode(boolean weakkeys, boolean weakvalues) { protected WeakTable changemode(boolean weakkeys, boolean weakvalues) {
@@ -84,7 +83,7 @@ public class WeakTable extends LuaTable {
public void rawset( int key, LuaValue value ) { public void rawset( int key, LuaValue value ) {
if ( weakvalues ) if ( weakvalues )
value = weaken( value ); value = weaken( value );
backing.set(key, value); super.rawset(key, value);
} }
/** caller must ensure key is not nil */ /** caller must ensure key is not nil */
@@ -103,26 +102,43 @@ public class WeakTable extends LuaTable {
break; break;
} }
} }
backing.set(key, value); super.rawset(key, value);
} }
public LuaValue rawget( int key ) { public LuaValue rawget( int key ) {
return rawget(valueOf(key)); LuaValue v = super.rawget(key).strongvalue();
}
public LuaValue rawget( LuaValue key ) {
LuaValue v = backing.rawget(key);
if ( v.isnil() ) if ( v.isnil() )
return NIL; super.rawset(key, NIL);
v = v.strongvalue();
if ( v.isnil() )
backing.rawset(key, NIL);
return v; return v;
} }
public LuaValue rawget( LuaValue key ) {
LuaValue v = super.rawget(key).strongvalue();
if ( v.isnil() )
super.rawset(key, NIL);
return v;
}
// 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 ( i<hashKeys.length && ( k = hashKeys[i] ) != null ) {
if ( k.isnil() ) {
hashClearSlot(i);
}
else {
if ( k.eq_b(key) )
return i;
i = ( i + 1 ) % hashKeys.length;
}
}
return i;
}
public int maxn() { public int maxn() {
return backing.maxn(); return super.maxn();
} }
@@ -132,14 +148,14 @@ public class WeakTable extends LuaTable {
*/ */
public Varargs next( LuaValue key ) { public Varargs next( LuaValue key ) {
while ( true ) { while ( true ) {
Varargs n = backing.next(key); Varargs n = super.next(key);
LuaValue k = n.arg1(); LuaValue k = n.arg1();
if ( k.isnil() ) if ( k.isnil() )
return NIL; return NIL;
LuaValue ks = k.strongkey(); LuaValue ks = k.strongkey();
LuaValue vs = n.arg(2).strongvalue(); LuaValue vs = n.arg(2).strongvalue();
if ( ks.isnil() || vs.isnil() ) { if ( ks.isnil() || vs.isnil() ) {
backing.rawset(ks, NIL); super.rawset(ks, NIL);
} else { } else {
return varargsOf(ks,vs); return varargsOf(ks,vs);
} }
@@ -159,7 +175,7 @@ public class WeakTable extends LuaTable {
// ----------------- sort support ----------------------------- // ----------------- sort support -----------------------------
public void sort(final LuaValue comparator) { public void sort(final LuaValue comparator) {
backing.sort( new TwoArgFunction() { super.sort( new TwoArgFunction() {
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return comparator.call( arg1.strongvalue(), arg2.strongvalue() ); return comparator.call( arg1.strongvalue(), arg2.strongvalue() );
} }
@@ -201,17 +217,20 @@ public class WeakTable extends LuaTable {
Object o = ref.get(); Object o = ref.get();
return o!=null && rhs.eq_b((LuaValue)o); return o!=null && rhs.eq_b((LuaValue)o);
} }
public boolean isnil() {
return ref.get() == null;
}
} }
static final class WeakUserdata extends WeakValue { static final class WeakUserdata extends WeakValue {
private final WeakReference ob; private final WeakReference ob;
private final WeakReference mt; private final LuaValue mt;
private WeakUserdata(LuaValue value) { private WeakUserdata(LuaValue value) {
super(value); super(value);
ob = new WeakReference(value.touserdata()); ob = new WeakReference(value.touserdata());
LuaValue udmt = value.getmetatable(); mt = value.getmetatable();
mt = udmt!=null? new WeakReference(udmt): null;
} }
public LuaValue strongvalue() { public LuaValue strongvalue() {
@@ -219,8 +238,7 @@ 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();
Object m = mt!=null? mt.get(): null; return o!=null? userdataOf(o,mt): NIL;
return o!=null? m!=null? userdataOf(o,(LuaValue)m): userdataOf(o): NIL;
} }
public boolean eq_b(LuaValue rhs) { public boolean eq_b(LuaValue rhs) {
@@ -234,34 +252,28 @@ public class WeakTable extends LuaTable {
public Object touserdata() { public Object touserdata() {
return ob.get(); return ob.get();
} }
public boolean isnil() {
return ob.get() == null || ref.get() == null;
}
} }
static final class WeakEntry extends LuaValue { static final class WeakEntry extends LuaValue {
final WeakTable table;
final LuaValue weakkey; final LuaValue weakkey;
LuaValue weakvalue;
final int keyhash; final int keyhash;
private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) { private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) {
this.table = table;
this.weakkey = table.weaken(key); this.weakkey = table.weaken(key);
this.keyhash = key.hashCode(); this.keyhash = key.hashCode();
this.weakvalue = weakvalue;
// store an association from table to value in the key's metatable
LuaValue mt = key.getmetatable();
if ( mt == null )
key.setmetatable(mt=new LuaTable(0,1));
mt.set(table, weakvalue);
} }
// when looking up the value, look in the keys metatable // when looking up the value, look in the keys metatable
public LuaValue strongvalue() { public LuaValue strongvalue() {
LuaValue key = weakkey.strongkey(); LuaValue key = weakkey.strongkey();
if ( key.isnil() ) if ( key.isnil() )
return NIL; return weakvalue = NIL;
LuaValue mt = key.getmetatable();
if ( mt == null )
return NIL;
LuaValue weakvalue = mt.get(table);
return weakvalue.strongvalue(); return weakvalue.strongvalue();
} }
@@ -287,5 +299,9 @@ public class WeakTable extends LuaTable {
public boolean eq_b(LuaValue rhs) { public boolean eq_b(LuaValue rhs) {
return rhs.eq_b(weakkey.strongkey()); return rhs.eq_b(weakkey.strongkey());
} }
public boolean isnil() {
return weakkey.isnil() || weakvalue.isnil();
}
} }
} }

View File

@@ -121,7 +121,7 @@ abstract public class WeakTableTest extends TableTest {
key = LuaValue.userdataOf(new MyData(111)); key = LuaValue.userdataOf(new MyData(111));
val = LuaValue.userdataOf(new MyData(222)); val = LuaValue.userdataOf(new MyData(222));
// new key and value should be interchangeable (feature of this test class // new key and value should be interchangeable (feature of this test class)
assertEquals( key, origkey.get() ); assertEquals( key, origkey.get() );
assertEquals( val, origval.get() ); assertEquals( val, origval.get() );
assertEquals( val, t.get(key) ); assertEquals( val, t.get(key) );
@@ -131,8 +131,9 @@ abstract public class WeakTableTest extends TableTest {
// value should not be reachable after gc // value should not be reachable after gc
collectGarbage(); collectGarbage();
assertEquals( null, origkey.get() ); assertEquals( null, origkey.get() );
assertEquals( null, origval.get() );
assertEquals( LuaValue.NIL, t.get(key) ); assertEquals( LuaValue.NIL, t.get(key) );
collectGarbage();
assertEquals( null, origval.get() );
} }
} }