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; }
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; }
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); }
Object* LookupTable::remove(STATE, Object* key) { hashval bin; Object* val; Tuple* entry; Tuple* lst; key_to_sym(key); 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); } bin = find_bin(key_hash(key), num_bins); entry = try_as<Tuple>(values_->at(state, bin)); lst = NULL; while(entry) { Object* link = entry->at(state, 2); if(entry->at(state, 0) == key) { val = entry->at(state, 1); if(lst) { lst->put(state, 2, link); } else { values_->put(state, bin, link); } entries(state, Fixnum::from(entries_->to_native() - 1)); return val; } lst = entry; entry = try_as<Tuple>(link); } return Qnil; }
Tuple* LookupTable::find_entry(STATE, Object* key) { unsigned int bin; Tuple* entry; key_to_sym(key); bin = find_bin(key_hash(key), bins_->to_native()); /* HACK: This should be fixed by not storing NULLs */ Object* data = values_->at(state, bin); if (!data) return NULL; entry = try_as<Tuple>(data); while(entry) { if(entry->at(state, 0) == key) { return entry; } entry = try_as<Tuple>(entry->at(state, 2)); } return NULL; }
Object* LookupTable::store(STATE, Object* key, Object* val) { unsigned int num_entries, num_bins, bin; Object* new_ent; Tuple* cur; Tuple* entry; key_to_sym(key); num_entries = entries_->to_native(); num_bins = bins_->to_native(); if(max_density_p(num_entries, num_bins)) { redistribute(state, num_bins <<= 1); } bin = find_bin(key_hash(key), num_bins); cur = entry = try_as<Tuple>(values_->at(state, bin)); while(entry) { if(entry->at(state, 0) == key) { entry->put(state, 1, val); return val; } cur = entry; entry = try_as<Tuple>(entry->at(state, 2)); } new_ent = entry_new(state, key, val); if(cur) { cur->put(state, 2, new_ent); } else { values_->put(state, bin, new_ent); } entries(state, Fixnum::from(num_entries + 1)); return val; }