public LuaValue setmetatable(LuaValue metatable) { boolean hadWeakKeys = m_metatable != null && m_metatable.useWeakKeys(); boolean hadWeakValues = m_metatable != null && m_metatable.useWeakValues(); m_metatable = metatableOf(metatable); if ((hadWeakKeys != (m_metatable != null && m_metatable.useWeakKeys())) || (hadWeakValues != (m_metatable != null && m_metatable.useWeakValues()))) { // force a rehash rehash(0); } return this; }
/** * Set a hashtable value * * @param key key to set * @param value value to set */ public void hashset(LuaValue key, LuaValue value) { if (value.isnil()) hashRemove(key); else { int index = 0; if (hash.length > 0) { index = hashSlot(key); for (Slot slot = hash[index]; slot != null; slot = slot.rest()) { StrongSlot foundSlot; if ((foundSlot = slot.find(key)) != null) { hash[index] = hash[index].set(foundSlot, value); return; } } } if (checkLoadFactor()) { if (key.isinttype() && key.toint() > 0) { // a rehash might make room in the array portion for this key. rehash(key.toint()); if (arrayset(key.toint(), value)) return; } else { rehash(-1); } index = hashSlot(key); } Slot entry = (m_metatable != null) ? m_metatable.entry(key, value) : defaultEntry(key, value); hash[index] = (hash[index] != null) ? hash[index].add(entry) : entry; ++hashEntries; } }
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)); }
/** * Sort the table using a comparator. * * @param comparator {@link LuaValue} to be called to compare elements. */ public void sort(LuaValue comparator) { if (m_metatable != null && m_metatable.useWeakValues()) { dropWeakArrayValues(); } int n = array.length; while (n > 0 && array[n - 1] == null) --n; if (n > 1) heapSort(n, comparator); }
/** Set an array element */ private boolean arrayset(int key, LuaValue value) { if (key > 0 && key <= array.length) { array[key - 1] = value.isnil() ? null : (m_metatable != null ? m_metatable.wrap(value) : value); return true; } return false; }
public LuaValue rawget(LuaValue key) { if (key.isinttype()) { int ikey = key.toint(); if (ikey > 0 && ikey <= array.length) { LuaValue v = m_metatable == null ? array[ikey - 1] : m_metatable.arrayget(array, ikey - 1); return v != null ? v : NIL; } } return hashget(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; }
private boolean compare(int i, int j, LuaValue cmpfunc) { LuaValue a, b; if (m_metatable == null) { a = array[i]; b = array[j]; } else { a = m_metatable.arrayget(array, i); b = m_metatable.arrayget(array, j); } if (a == null || b == null) return false; if (!cmpfunc.isnil()) { return cmpfunc.call(a, b).toboolean(); } else { return a.lt_b(b); } }
public boolean eq_b(LuaValue val) { if (this == val) return true; if (m_metatable == null || !val.istable()) return false; LuaValue valmt = val.getmetatable(); return valmt != null && eqmtcall(this, m_metatable.toLuaValue(), val, valmt); }
/* * 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; }
private void dropWeakArrayValues() { for (int i = 0; i < array.length; ++i) { m_metatable.arrayget(array, i); } }
public LuaValue getmetatable() { return (m_metatable != null) ? m_metatable.toLuaValue() : null; }