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