1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-27 23:53:21 +00:00
CC-Tweaked/luaj-2.0.3/src/core/org/luaj/vm2/WeakTable.java
Daniel Ratcliffe e85cdacbc5 ComputerCraft 1.79 initial upload
Added the complete source code to ComputerCraft 1.79 for Minecraft
1.8.9, plus newly written README and LICENSE files for the open source
release.
2017-05-01 14:32:39 +01:00

350 lines
9.0 KiB
Java

/*******************************************************************************
* Copyright (c) 2009-2011 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 java.lang.ref.WeakReference;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
* <p>
* Normally these are not created directly, but indirectly when changing the mode
* of a {@link LuaTable} as lua script executes.
* <p>
* However, calling the constructors directly when weak tables are required from
* Java will reduce overhead.
*/
public class WeakTable extends LuaTable {
private boolean weakkeys,weakvalues;
/**
* Construct a table with weak keys, weak values, or both
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
*/
public WeakTable(boolean weakkeys, boolean weakvalues) {
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.weakvalues = weakvalues;
}
/**
* Construct a table with weak keys, weak values, or both, and a source of initial data
* @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 ) {
super.presize(narray);
}
/**
* Presize capacity of both array and hash parts.
* @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() {
return super.getArrayLength();
}
protected int getHashLength() {
return super.getHashLength();
}
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
this.weakkeys = weakkeys;
this.weakvalues = weakvalues;
return this;
}
/**
* Self-sent message to convert a value to its weak counterpart
* @param value value to convert
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
*/
LuaValue weaken( LuaValue value ) {
switch ( value.type() ) {
case LuaValue.TFUNCTION:
case LuaValue.TTHREAD:
case LuaValue.TTABLE:
return new WeakValue(value);
case LuaValue.TUSERDATA:
return new WeakUserdata(value);
default:
return value;
}
}
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;
}
public int maxn() {
return super.maxn();
}
/**
* Get the next element after a particular key in the table
* @return key,value or nil
*/
public Varargs next( LuaValue key ) {
while ( true ) {
Varargs n = super.next(key);
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);
}
}
}
// ----------------- sort support -----------------------------
public void sort(final LuaValue comparator) {
super.sort( new TwoArgFunction() {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return comparator.call( arg1.strongvalue(), arg2.strongvalue() );
}
} );
}
/** Internal class to implement weak values.
* @see WeakTable
*/
static class WeakValue extends LuaValue {
final WeakReference ref;
protected WeakValue(LuaValue value) {
ref = new WeakReference(value);
}
public int type() {
illegal("type","weak value");
return 0;
}
public String typename() {
illegal("typename","weak value");
return null;
}
public String toString() {
return "weak<"+ref.get()+">";
}
public LuaValue strongvalue() {
Object o = ref.get();
return o!=null? (LuaValue)o: NIL;
}
public boolean raweq(LuaValue rhs) {
Object o = ref.get();
return o!=null && rhs.raweq((LuaValue)o);
}
public boolean isweaknil() {
return ref.get() == null;
}
}
/** Internal class to implement weak userdata values.
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {
private final WeakReference ob;
private final LuaValue mt;
private WeakUserdata(LuaValue value) {
super(value);
ob = new WeakReference(value.touserdata());
mt = value.getmetatable();
}
public LuaValue strongvalue() {
Object u = ref.get();
if ( u != null )
return (LuaValue) u;
Object o = ob.get();
return o!=null? userdataOf(o,mt): NIL;
}
public boolean raweq(LuaValue rhs) {
if ( ! rhs.isuserdata() )
return false;
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.
* @see WeakTable
*/
static final class WeakEntry extends LuaValue {
final LuaValue weakkey;
LuaValue weakvalue;
final int keyhash;
private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) {
this.weakkey = table.weaken(key);
this.keyhash = key.hashCode();
this.weakvalue = weakvalue;
}
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();
}
}
}