예제 #1
0
 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;
 }
예제 #2
0
 /**
  * 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);
 }
예제 #3
0
  /*
   * 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;
  }