Simplify weak table implementation.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user