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:
@@ -170,7 +170,7 @@ public class TableLib extends LFunction {
|
|||||||
case MAXN: {
|
case MAXN: {
|
||||||
LTable table = vm.totable(2);
|
LTable table = vm.totable(2);
|
||||||
vm.resettop();
|
vm.resettop();
|
||||||
vm.pushinteger( table.luaMaxN() );
|
vm.pushlvalue( table.luaMaxN() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,28 +494,22 @@ public class LTable extends LValue {
|
|||||||
// getting bigger, and from array part to hash part if array is getting
|
// getting bigger, and from array part to hash part if array is getting
|
||||||
// smaller.
|
// smaller.
|
||||||
if ( newCapacity > oldCapacity ) {
|
if ( newCapacity > oldCapacity ) {
|
||||||
if ( m_hashKeys != null ) {
|
for ( int i = oldCapacity; i < newCapacity; ++i ) {
|
||||||
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 );
|
int slot = findSlot( i+1 );
|
||||||
if ( m_hashKeys[ slot ] != null ) {
|
if ( m_hashKeys[ slot ] != null ) {
|
||||||
newVector[ i ] = m_hashValues[ slot ];
|
newVector[ i ] = m_hashValues[ slot ];
|
||||||
m_hashKeys[ slot ] = null;
|
clearSlot( slot );
|
||||||
--m_hashEntries;
|
continue;
|
||||||
} else {
|
|
||||||
// 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 ) {
|
// Make sure all array-part values are initialized to nil
|
||||||
m_hashKeys = null;
|
// so that we can just do one compare instead of two
|
||||||
m_hashValues = null;
|
// whenever we need to check if a slot is full or not.
|
||||||
}
|
newVector[ i ] = LNil.NIL;
|
||||||
} else {
|
|
||||||
for ( int i = oldCapacity; i < newCapacity; ++i ) {
|
|
||||||
newVector[ i ] = LNil.NIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
||||||
@@ -586,8 +580,29 @@ public class LTable extends LValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int luaMaxN() {
|
public LValue luaMaxN() {
|
||||||
return m_arrayEntries;
|
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 -----------------------------
|
// ----------------- sort support -----------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user