From 527ca6545d6863b45ce09a86cd757a0fbfcb513b Mon Sep 17 00:00:00 2001 From: Ian Farmer Date: Wed, 23 Jan 2008 02:22:19 +0000 Subject: [PATCH] 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. --- src/core/org/luaj/lib/TableLib.java | 2 +- src/core/org/luaj/vm/LTable.java | 53 ++++++++++++++++++----------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/core/org/luaj/lib/TableLib.java b/src/core/org/luaj/lib/TableLib.java index fc7f624b..0d1241f4 100644 --- a/src/core/org/luaj/lib/TableLib.java +++ b/src/core/org/luaj/lib/TableLib.java @@ -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; } diff --git a/src/core/org/luaj/vm/LTable.java b/src/core/org/luaj/vm/LTable.java index bc8504b0..d1614288 100644 --- a/src/core/org/luaj/vm/LTable.java +++ b/src/core/org/luaj/vm/LTable.java @@ -494,28 +494,22 @@ 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 ) { + 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 { - // 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; + clearSlot( slot ); + continue; } } - if ( m_hashEntries == 0 ) { - m_hashKeys = null; - m_hashValues = null; - } - } else { - for ( int i = oldCapacity; i < newCapacity; ++i ) { - newVector[ i ] = LNil.NIL; - } + // 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; } } else { for ( int i = newCapacity; i < oldCapacity; ++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 -----------------------------