optimization for tables that include sequential integral indices starting with 0.

commented out: a more sophisticated (but space-consuming) optimization
that accounts for arbitrary starting index, stride, and direction (increasing/decreasing).

commented out some table metatable stuff that was wrong.  metatables
need to be implemented properly.
This commit is contained in:
Christopher Colby
2007-07-24 06:22:07 +00:00
parent 8bf4c82a12
commit b9fdb731fe
2 changed files with 145 additions and 29 deletions

View File

@@ -76,7 +76,7 @@ public class LuaCompat extends LFunction {
LValue k = vm.getArg(1); LValue k = vm.getArg(1);
LValue result = LNil.NIL; LValue result = LNil.NIL;
if ( t instanceof LTable ) { if ( t instanceof LTable ) {
LValue v = (LValue) ( (LTable) t ).m_hash.get( k ); LValue v = (LValue) ( (LTable) t ).rawGet( k );
if ( v != null ) { if ( v != null ) {
result = v; result = v;
} }

View File

@@ -2,6 +2,7 @@ package lua.value;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Vector;
import lua.VM; import lua.VM;
@@ -10,12 +11,25 @@ public class LTable extends LValue {
public static final LString TYPE_NAME = new LString("table"); public static final LString TYPE_NAME = new LString("table");
/** Metatable tag for intercepting table gets */ /** Metatable tag for intercepting table gets */
private static final LString TM_INDEX = new LString("__index"); // TODO: see note below
// private static final LString TM_INDEX = new LString("__index");
/** Metatable tag for intercepting table sets */ /** Metatable tag for intercepting table sets */
private static final LString TM_NEWINDEX = new LString("__newindex"); // TODO: see note below
// private static final LString TM_NEWINDEX = new LString("__newindex");
private Hashtable m_hash = new Hashtable();
private Vector m_vector; // if non-null then size() > 0
// stride and offset are needed only for the
// implementation where m_vector stores keys
// {offset, stride + offset, ..., (size-1)*stride + offset}
// where size = m_vector.size()
//
// private int stride = 1; // always non-0; if m_vector.size() == 1 then stride == 1
// private int offset; // if m_vector.size() == 1 then offset is the single integer key
public Hashtable m_hash = new Hashtable();
private LTable m_metatable; private LTable m_metatable;
public LTable() { public LTable() {
@@ -24,22 +38,71 @@ public class LTable extends LValue {
public LTable(int narray, int nhash) { public LTable(int narray, int nhash) {
} }
/** Utility method for putting a value directly, typically for initializing a table */ /** Utility method for putting a string-keyed value directly, typically for initializing a table */
public void put(String key, LValue value) { public void put(String key, LValue value) {
m_hash.put( new LString(key), value ); m_hash.put( new LString(key), value );
} }
/** Utility method for putting something in a numbered slot */ public void rawSet(LValue key, LValue val) {
public void put(int i, LValue value) {
m_hash.put( new Integer(i), value ); if (key instanceof LInteger) {
int iKey = ((LInteger) key).luaAsInt();
// implementation where m_vector stores keys
// {0, ..., size-1}
// where size = m_vector.size()
//
if (m_vector == null) {
if (iKey == 0) {
m_vector = new Vector();
m_vector.add(val);
return;
}
} else if (iKey >= 0) {
int size = m_vector.size();
if (iKey < size) {
m_vector.set(iKey, val);
return;
} else if (iKey == size) {
m_vector.add(iKey, val);
return;
}
} }
/** Utility method to directly get the value in a table, without metatable calls */ /*
public LValue get(String key) { // implementation where m_vector stores keys
return (LValue) m_hash.get( new LString(key) ); // {offset, stride + offset, ..., (size-1)*stride + offset}
// where size = m_vector.size()
//
if (m_vector == null) {
offset = iKey;
m_vector = new Vector();
m_vector.add(val);
return;
} else {
int size = m_vector.size();
int multiple = iKey - offset;
if (multiple >= 0) {
int i = multiple / stride;
if ((i < size) && (i * stride == multiple)) {
m_vector.set(i, val);
return;
}
} else if (size == 1) {
stride = iKey - offset;
m_vector.add(val);
return;
} else if (iKey == stride * size + offset) {
m_vector.add(val);
return;
}
}
*/
} }
public void luaSetTable(VM vm, LValue table, LValue key, LValue val) { m_hash.put( key, val );
/* TODO: this is old incorrect code, kept here until metatables are fixed
if ( m_metatable != null ) { if ( m_metatable != null ) {
if ( ! m_hash.containsKey(key) ) { if ( ! m_hash.containsKey(key) ) {
LValue event = (LValue) m_metatable.m_hash.get( TM_NEWINDEX ); LValue event = (LValue) m_metatable.m_hash.get( TM_NEWINDEX );
@@ -49,11 +112,45 @@ public class LTable extends LValue {
} }
} }
} }
m_hash.put( key, val ); */
} }
public void luaGetTable(VM vm, LValue table, LValue key) { /** Utility method to directly get the value in a table, without metatable calls */
LValue val = (LValue) m_hash.get(key); public LValue rawGet(LValue key) {
if (m_vector != null) {
if (key instanceof LInteger) {
int iKey = ((LInteger) key).luaAsInt();
// implementation where m_vector stores keys
// {0, ..., size-1}
// where size = m_vector.size()
//
if ((iKey >= 0) && (iKey < m_vector.size())) {
return (LValue) m_vector.get(iKey);
}
/*
// implementation where m_vector stores keys
// {offset, stride + offset, ..., (size-1)*stride + offset}
// where size = m_vector.size()
//
int multiple = iKey - offset;
if (multiple >= 0) {
int i = multiple / stride;
if ((i < m_vector.size()) && (i * stride == multiple)) {
vm.push((LValue) m_vector.get(i));
return;
}
}
*/
}
}
return (LValue) m_hash.get(key);
/* TODO: this is old incorrect code, kept here until metatables are fixed
LValue val;
if ( val == null || val == LNil.NIL ) { if ( val == null || val == LNil.NIL ) {
if ( m_metatable != null ) { if ( m_metatable != null ) {
LValue event = (LValue) m_metatable.m_hash.get( TM_INDEX ); LValue event = (LValue) m_metatable.m_hash.get( TM_INDEX );
@@ -64,14 +161,26 @@ public class LTable extends LValue {
} }
val = LNil.NIL; val = LNil.NIL;
} }
return val;
// stack.stack[base] = val; */
vm.push(val);
} }
public void luaGetTable(VM vm, LValue table, LValue key) {
// TODO: table is unused -- is this correct?
// stack.stack[base] = val;
vm.push(rawGet(key));
}
public void luaSetTable(VM vm, LValue table, LValue key, LValue val) {
// TODO: table is unused -- is this correct?
rawSet(key, val);
}
/* TODO: why was this overridden in the first place?
public String toString() { public String toString() {
return m_hash.toString(); return m_hash.toString();
} }
*/
public String luaAsString() { public String luaAsString() {
return "table: "+id(); return "table: "+id();
@@ -79,7 +188,9 @@ public class LTable extends LValue {
/** Built-in opcode LEN, for Strings and Tables */ /** Built-in opcode LEN, for Strings and Tables */
public LValue luaLength() { public LValue luaLength() {
return new LInteger( m_hash.size() ); int hashSize = m_hash.size();
return new LInteger(
m_vector == null ? hashSize : hashSize + m_vector.size());
} }
/** Valid for tables */ /** Valid for tables */
@@ -94,28 +205,33 @@ public class LTable extends LValue {
/** Valid for tables */ /** Valid for tables */
public LValue luaPairs() { public LValue luaPairs() {
Enumeration e = m_hash.keys(); return new LTableIterator(this);
return new LTableIterator(this,e);
} }
/** Iterator for tables */ /** Iterator for tables */
private static final class LTableIterator extends LFunction { private static final class LTableIterator extends LFunction {
private final LTable t; private final LTable t;
private final Enumeration e; private final Enumeration e;
private int i;
private LTableIterator(LTable t, Enumeration e) { private LTableIterator(LTable t) {
this.t = t; this.t = t;
this.e = e; this.e = t.m_hash.keys();
this.i = (t.m_vector == null) ? -1 : 0;
} }
// perform a lua call // perform a lua call
public void luaStackCall(VM vm) { public void luaStackCall(VM vm) {
if ( e.hasMoreElements() ) { if ( e.hasMoreElements() ) {
LValue key = (LValue) e.nextElement(); LValue key = (LValue) e.nextElement();
LValue val = (LValue) t.m_hash.get(key);
vm.setResult(); vm.setResult();
vm.push( key ); vm.push( key );
vm.push( val ); vm.push((LValue) t.m_hash.get(key));
} else if ((i >= 0) && (i < t.m_vector.size())) {
vm.setResult();
vm.push(new LInteger(i));
vm.push((LValue) t.m_vector.get(i));
++i;
} }
} }
} }