예제 #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
 /**
  * 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;
   }
 }
예제 #3
0
 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));
 }
예제 #4
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);
 }
예제 #5
0
 /** 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;
 }
예제 #6
0
 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);
 }
예제 #7
0
  /**
   * 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;
  }
예제 #8
0
 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);
   }
 }
예제 #9
0
 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);
 }
예제 #10
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;
  }
예제 #11
0
 private void dropWeakArrayValues() {
   for (int i = 0; i < array.length; ++i) {
     m_metatable.arrayget(array, i);
   }
 }
예제 #12
0
 public LuaValue getmetatable() {
   return (m_metatable != null) ? m_metatable.toLuaValue() : null;
 }