Example #1
0
  Object* LookupTable::store(STATE, Object* key, Object* val) {
    unsigned int num_entries, num_bins, bin;
    LookupTableBucket* entry;
    LookupTableBucket* last = NULL;

    num_entries = entries_->to_native();
    num_bins = bins_->to_native();

    if(max_density_p(num_entries, num_bins)) {
      redistribute(state, num_bins <<= 1);
    }

    key_to_sym(key);
    bin = find_bin(key_hash(key), num_bins);
    entry = try_as<LookupTableBucket>(values_->at(state, bin));

    while(entry) {
      if(entry->key() == key) {
        entry->value(state, val);
        return val;
      }
      last = entry;
      entry = try_as<LookupTableBucket>(entry->next());
    }

    if(last) {
      last->next(state, LookupTableBucket::create(state, key, val));
    } else {
      values_->put(state, bin, LookupTableBucket::create(state, key, val));
    }

    entries(state, Fixnum::from(num_entries + 1));
    return val;
  }
Example #2
0
  Object* LookupTable::remove(STATE, Object* key, bool* removed) {
    hashval bin;
    LookupTableBucket* entry;
    LookupTableBucket* last = NULL;

    size_t num_entries = entries_->to_native();
    size_t num_bins = bins_->to_native();

    if(min_density_p(num_entries, num_bins) && (num_bins >> 1) >= LOOKUPTABLE_MIN_SIZE) {
      redistribute(state, num_bins >>= 1);
    }

    key_to_sym(key);
    bin = find_bin(key_hash(key), num_bins);
    entry = try_as<LookupTableBucket>(values_->at(state, bin));

    while(entry) {
      if(entry->key() == key) {
        Object *val = entry->value();
        if(last) {
          last->next(state, entry->next());
        } else {
          values_->put(state, bin, entry->next());
        }
        entries(state, Fixnum::from(entries_->to_native() - 1));
        if(removed) *removed = true;
        return val;
      }

      last = entry;
      entry = try_as<LookupTableBucket>(entry->next());
    }

    return Qnil;
  }
Example #3
0
  void LookupTable::redistribute(STATE, size_t size) {
    size_t num = bins_->to_native();
    Tuple* new_values = Tuple::create(state, size);

    for(size_t i = 0; i < num; i++) {
      LookupTableBucket* entry = try_as<LookupTableBucket>(values_->at(state, i));

      while(entry) {
        LookupTableBucket* link = try_as<LookupTableBucket>(entry->next());
        entry->next(state, reinterpret_cast<LookupTableBucket *>(Qnil));

        size_t bin = find_bin(key_hash(entry->key()), size);
        LookupTableBucket* slot = try_as<LookupTableBucket>(new_values->at(state, bin));

        if(slot) {
          slot->append(state, entry);
        } else {
          new_values->put(state, bin, entry);
        }

        entry = link;
      }
    }

    values(state, new_values);
    bins(state, Fixnum::from(size));
  }
Example #4
0
  Object* LookupTableBucket::append(STATE, LookupTableBucket* nxt) {
    LookupTableBucket* cur = try_as<LookupTableBucket>(this->next());
    LookupTableBucket* last = this;

    while(cur) {
      last = cur;
      cur = try_as<LookupTableBucket>(cur->next());
    }

    last->next(state, nxt);
    return nxt;
  }
  void test_store_handles_entries_in_same_bin() {
    Object* k1 = Fixnum::from((4 << 4)  | 15);
    Object* k2 = Fixnum::from((10 << 4) | 15);
    Object* k3 = Fixnum::from((11 << 4) | 15);
    Object* v1 = cTrue;
    Object* v2 = cFalse;
    Object* v3 = cTrue;

    tbl->store(state, k1, v1);
    tbl->store(state, k2, v2);
    tbl->store(state, k3, v3);
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 3);

    LookupTableBucket* entry = tbl->find_entry(state, k1);
    TS_ASSERT(entry != cNil);

    TS_ASSERT(entry->next() != cNil);
    TS_ASSERT_EQUALS(entry->next()->key(), k2);

    entry = tbl->find_entry(state, k3);
    TS_ASSERT(entry != cNil);
    TS_ASSERT_EQUALS(entry->key(), k3);
  }
Example #6
0
  LookupTableBucket* LookupTable::find_entry(STATE, Object* key) {
    unsigned int bin;

    key_to_sym(key);
    bin = find_bin(key_hash(key), bins_->to_native());
    LookupTableBucket *entry = try_as<LookupTableBucket>(values_->at(state, bin));

    while(entry) {
      if(entry->key() == key) {
        return entry;
      }
      entry = try_as<LookupTableBucket>(entry->next());
    }
    return reinterpret_cast<LookupTableBucket *>(Qnil);
  }
Example #7
0
Array* LookupTable::collect(STATE, LookupTable* tbl,
                            Object* (*action)(STATE, LookupTableBucket*))
{
    size_t i, j;
    Tuple* values;

    Array* ary = Array::create(state, tbl->entries()->to_native());
    size_t num_bins = tbl->bins()->to_native();
    values = tbl->values();

    for(i = j = 0; i < num_bins; i++) {
        LookupTableBucket* entry = try_as<LookupTableBucket>(values->at(state, i));

        while(entry) {
            ary->set(state, j++, action(state, entry));
            entry = try_as<LookupTableBucket>(entry->next());
        }
    }
    return ary;
}
Example #8
0
  Array* LookupTable::collect(STATE, LookupTable* tbl, CollectAction& action)
  {
    size_t i, j;
    Tuple* values;
    LookupTableBucket* entry;

    Array* ary = Array::create(state, tbl->entries()->to_native());
    size_t num_bins = tbl->bins()->to_native();
    values = tbl->values();

    for(i = j = 0; i < num_bins; i++) {
      entry = try_as<LookupTableBucket>(values->at(state, i));

      while(entry) {
        Object* ret = action.call(state, entry);
        if(ret) ary->set(state, j++, ret);
        entry = try_as<LookupTableBucket>(entry->next());
      }
    }
    return ary;
  }