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; }
/* lookuptable_find returns Qundef if there is not entry * referenced by 'key' in the LookupTable. This is useful * to distinguish x = {} from x = {:a => nil} and is used * in cpu.c in e.g. cpu_const_get_in_context. */ Object* LookupTable::find(STATE, Object* key) { LookupTableBucket* entry = find_entry(state, key); if(entry == Qnil) { return Qundef; } return entry->value(); }
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* LookupTableBucket::create(STATE, Object *key, Object *value) { LookupTableBucket *entry = state->new_object<LookupTableBucket>(G(lookuptablebucket)); entry->key(state, key); entry->value(state, value); return entry; }
Object* LookupTable::fetch(STATE, Object* key, Object* return_on_failure) { LookupTableBucket* entry = find_entry(state, key); if(entry == Qnil) { return return_on_failure; } return entry->value(); }
Object* LookupTable::fetch(STATE, Object* key, bool* found) { LookupTableBucket* entry = find_entry(state, key); if(entry == Qnil) { *found = false; return Qnil; } *found = true; return entry->value(); }
void test_find_entry() { Object* k = Fixnum::from(47); tbl->store(state, k, cTrue); LookupTableBucket* entry = tbl->find_entry(state, k); TS_ASSERT(entry != cNil); TS_ASSERT_EQUALS(entry->key(),k); TS_ASSERT_EQUALS(entry->value(),cTrue); entry = tbl->find_entry(state, Fixnum::from(40)); TS_ASSERT(entry == cNil); }
LookupTable* LookupTable::duplicate(STATE) { size_t size, i; LookupTable *dup; size = bins_->to_native(); dup = LookupTable::create(state, size); // Allow for subclassing. dup->klass(state, class_object(state)); size_t num = entries_->to_native(); Array* entries = all_entries(state); for(i = 0; i < num; i++) { LookupTableBucket* entry = as<LookupTableBucket>(entries->get(state, i)); dup->store(state, entry->key(), entry->value()); } return dup; }
/** Same as aref(state, key). */ Object* LookupTable::fetch(STATE, Object* key) { LookupTableBucket* entry = find_entry(state, key); if(entry == Qnil) return Qnil; return entry->value(); }
/** Same as fetch(state, key). */ Object* LookupTable::aref(STATE, Object* key) { LookupTableBucket* entry = find_entry(state, key); if(entry == cNil) return cNil; return entry->value(); }