Fix bugs in LTable.

Two issues:
(1) When resizing, clearSlot() needs to be used to correctly move
affected hash entries.
(2) table.maxn is documented as returning the largest numeric key in
the table. This requires a linear scan through the entire table, but
the Lua documentation explicitly warns about that.
This commit is contained in:
Ian Farmer
2008-01-23 02:22:19 +00:00
parent 4fa417bdd9
commit 527ca6545d
2 changed files with 35 additions and 20 deletions

View File

@@ -170,7 +170,7 @@ public class TableLib extends LFunction {
case MAXN: {
LTable table = vm.totable(2);
vm.resettop();
vm.pushinteger( table.luaMaxN() );
vm.pushlvalue( table.luaMaxN() );
break;
}

View File

@@ -494,29 +494,23 @@ public class LTable extends LValue {
// getting bigger, and from array part to hash part if array is getting
// smaller.
if ( newCapacity > oldCapacity ) {
if ( m_hashKeys != null ) {
for ( int i = oldCapacity; i < newCapacity; ++i ) {
// Test for m_hashKeys != null must be inside the loop because
// call to clearSlot may result in m_hashKeys becoming null
// at any time.
if ( m_hashKeys != null ) {
int slot = findSlot( i+1 );
if ( m_hashKeys[ slot ] != null ) {
newVector[ i ] = m_hashValues[ slot ];
m_hashKeys[ slot ] = null;
--m_hashEntries;
} else {
clearSlot( slot );
continue;
}
}
// Make sure all array-part values are initialized to nil
// so that we can just do one compare instead of two
// whenever we need to check if a slot is full or not.
newVector[ i ] = LNil.NIL;
}
}
if ( m_hashEntries == 0 ) {
m_hashKeys = null;
m_hashValues = null;
}
} else {
for ( int i = oldCapacity; i < newCapacity; ++i ) {
newVector[ i ] = LNil.NIL;
}
}
} else {
for ( int i = newCapacity; i < oldCapacity; ++i ) {
LValue v = m_vector[i];
@@ -586,8 +580,29 @@ public class LTable extends LValue {
}
}
public int luaMaxN() {
return m_arrayEntries;
public LValue luaMaxN() {
LValue result = LInteger.valueOf(0);
for ( int i = m_vector.length - 1; i >= 0; i-- ) {
if ( m_vector[i] != LNil.NIL ) {
result = LInteger.valueOf(i + 1);
break;
}
}
if ( m_hashKeys != null ) {
final int hlen = m_hashKeys.length;
for ( int i = 0; i < hlen; ++i ) {
LValue k = m_hashKeys[i];
if ( k != null && k.luaGetType() == Lua.LUA_TNUMBER ) {
if ( k.luaBinCmpUnknown(Lua.OP_LT, result ) ) {
result = k;
}
}
}
}
return result;
}
// ----------------- sort support -----------------------------