public LuaValue rawget(int key) { if (key > 0 && key <= array.length) { LuaValue v = m_metatable == null ? array[key - 1] : m_metatable.arrayget(array, key - 1); return v != null ? v : NIL; } return hashget(LuaInteger.valueOf(key)); }
/** * Get the next element after a particular key in the table * * @return key,value or nil */ public Varargs next(LuaValue key) { int i = 0; do { // find current key index if (!key.isnil()) { if (key.isinttype()) { i = key.toint(); if (i > 0 && i <= array.length) { break; } } if (hash.length == 0) error("invalid key to 'next'"); i = hashSlot(key); boolean found = false; for (Slot slot = hash[i]; slot != null; slot = slot.rest()) { if (found) { StrongSlot nextEntry = slot.first(); if (nextEntry != null) { return nextEntry.toVarargs(); } } else if (slot.keyeq(key)) { found = true; } } if (!found) { error("invalid key to 'next'"); } i += 1 + array.length; } } while (false); // check array part for (; i < array.length; ++i) { if (array[i] != null) { LuaValue value = m_metatable == null ? array[i] : m_metatable.arrayget(array, i); if (value != null) { return varargsOf(LuaInteger.valueOf(i + 1), value); } } } // check hash part for (i -= array.length; i < hash.length; ++i) { Slot slot = hash[i]; while (slot != null) { StrongSlot first = slot.first(); if (first != null) return first.toVarargs(); slot = slot.rest(); } } // nothing found, push nil, return nil. return NIL; }
/* * newKey > 0 is next key to insert * newKey == 0 means number of keys not changing (__mode changed) * newKey < 0 next key will go in hash part */ private void rehash(int newKey) { if (m_metatable != null && (m_metatable.useWeakKeys() || m_metatable.useWeakValues())) { // If this table has weak entries, hashEntries is just an upper bound. hashEntries = countHashKeys(); if (m_metatable.useWeakValues()) { dropWeakArrayValues(); } } int[] nums = new int[32]; int total = countIntKeys(nums); if (newKey > 0) { total++; nums[log2(newKey)]++; } // Choose N such that N <= sum(nums[0..log(N)]) < 2N int keys = nums[0]; int newArraySize = 0; for (int log = 1; log < 32; ++log) { keys += nums[log]; if (total * 2 < 1 << log) { // Not enough integer keys. break; } else if (keys >= (1 << (log - 1))) { newArraySize = 1 << log; } } final LuaValue[] oldArray = array; final Slot[] oldHash = hash; final LuaValue[] newArray; final Slot[] newHash; // Copy existing array entries and compute number of moving entries. int movingToArray = 0; if (newKey > 0 && newKey <= newArraySize) { movingToArray--; } if (newArraySize != oldArray.length) { newArray = new LuaValue[newArraySize]; if (newArraySize > oldArray.length) { for (int i = log2(oldArray.length + 1), j = log2(newArraySize) + 1; i < j; ++i) { movingToArray += nums[i]; } } else if (oldArray.length > newArraySize) { for (int i = log2(newArraySize + 1), j = log2(oldArray.length) + 1; i < j; ++i) { movingToArray -= nums[i]; } } System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newArraySize)); } else { newArray = array; } final int newHashSize = hashEntries - movingToArray + ((newKey < 0 || newKey > newArraySize) ? 1 : 0); // Make room for the new entry final int oldCapacity = oldHash.length; final int newCapacity; final int newHashMask; if (newHashSize > 0) { // round up to next power of 2. newCapacity = (newHashSize < MIN_HASH_CAPACITY) ? MIN_HASH_CAPACITY : 1 << log2(newHashSize); newHashMask = newCapacity - 1; newHash = new Slot[newCapacity]; } else { newCapacity = 0; newHashMask = 0; newHash = NOBUCKETS; } // Move hash buckets for (int i = 0; i < oldCapacity; ++i) { for (Slot slot = oldHash[i]; slot != null; slot = slot.rest()) { int k; if ((k = slot.arraykey(newArraySize)) > 0) { StrongSlot entry = slot.first(); if (entry != null) newArray[k - 1] = entry.value(); } else { int j = slot.keyindex(newHashMask); newHash[j] = slot.relink(newHash[j]); } } } // Move array values into hash portion for (int i = newArraySize; i < oldArray.length; ) { LuaValue v; if ((v = oldArray[i++]) != null) { int slot = hashmod(LuaInteger.hashCode(i), newHashMask); Slot newEntry; if (m_metatable != null) { newEntry = m_metatable.entry(valueOf(i), v); if (newEntry == null) continue; } else { newEntry = defaultEntry(valueOf(i), v); } newHash[slot] = (newHash[slot] != null) ? newHash[slot].add(newEntry) : newEntry; } } hash = newHash; array = newArray; hashEntries -= movingToArray; }
/** * Get the next element after a particular key in the contiguous array part of a table * * @return key,value or none */ public Varargs inext(LuaValue key) { int k = key.checkint() + 1; LuaValue v = rawget(k); return v.isnil() ? NONE : varargsOf(LuaInteger.valueOf(k), v); }
public LuaValue len() { return LuaInteger.valueOf(length()); }
public void rawset(int key, LuaValue value) { if (!arrayset(key, value)) hashset(LuaInteger.valueOf(key), value); }
public void set(int key, LuaValue value) { if (m_metatable == null || !rawget(key).isnil() || !settable(this, LuaInteger.valueOf(key), value)) rawset(key, value); }
public int keyindex(int mask) { return hashmod(LuaInteger.hashCode(key), mask); }
public LuaValue mul(int lhs) { return LuaInteger.valueOf(lhs * (long) v); }
public LuaValue subFrom(int lhs) { return LuaInteger.valueOf(lhs - (long) v); }
public LuaValue add(int lhs) { return LuaInteger.valueOf(lhs + (long) v); }