class ObjectSpace::WeakKeyMap
Ein ObjectSpace::WeakKeyMap ist eine Schlüssel-Wert-Zuordnung, die schwache Referenzen auf ihre Schlüssel speichert, sodass sie vom Garbage Collector eingesammelt werden können, wenn keine Referenzen mehr vorhanden sind.
Im Gegensatz zu ObjectSpace::WeakMap
-
sind Referenzen auf Werte stark, sodass sie nicht vom Garbage Collector eingesammelt werden, solange sie sich in der Zuordnung befinden;
-
Schlüssel werden nach Wert (mittels
Object#eql?) und nicht nach Identität verglichen; -
nur garbage-collectable Objekte können als Schlüssel verwendet werden.
map = ObjectSpace::WeakKeyMap.new val = Time.new(2023, 12, 7) key = "name" map[key] = val # Value is fetched by equality: the instance of string "name" is # different here, but it is equal to the key map["name"] #=> 2023-12-07 00:00:00 +0200 val = nil GC.start # There are no more references to `val`, yet the pair isn't # garbage-collected. map["name"] #=> 2023-12-07 00:00:00 +0200 key = nil GC.start # There are no more references to `key`, key and value are # garbage-collected. map["name"] #=> nil
(Beachten Sie, dass GC.start hier nur zu Demonstrationszwecken verwendet wird und möglicherweise nicht immer zu den gezeigten Ergebnissen führt.)
Die Sammlung ist besonders nützlich für die Implementierung von Caches für leichtgewichtige Wertobjekte, sodass nur eine Kopie jeder Wertdarstellung im Speicher gespeichert wird, aber die nicht verwendeten Kopien vom Garbage Collector eingesammelt würden.
CACHE = ObjectSpace::WeakKeyMap def make_value(**) val = ValueObject.new(**) if (existing = @cache.getkey(val)) # if the object with this value exists, we return it existing else # otherwise, put it in the cache @cache[val] = true val end end
Dies führt dazu, dass make_value immer dasselbe Objekt für denselben Satz von Attributen zurückgibt, aber die nicht mehr benötigten Werte würden nicht für immer im Cache verbleiben.
Öffentliche Instanzmethoden
Source
static VALUE
wkmap_aref(VALUE self, VALUE key)
{
VALUE obj = wkmap_lookup(self, key);
return !UNDEF_P(obj) ? obj : Qnil;
}
Gibt den zugeordneten Wert für den gegebenen key zurück, wenn gefunden.
Wenn key nicht gefunden wird, wird nil zurückgegeben.
Source
static VALUE
wkmap_aset(VALUE self, VALUE key, VALUE val)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
if (!FL_ABLE(key) || SYMBOL_P(key) || RB_BIGNUM_TYPE_P(key) || RB_TYPE_P(key, T_FLOAT)) {
rb_raise(rb_eArgError, "WeakKeyMap keys must be garbage collectable");
UNREACHABLE_RETURN(Qnil);
}
struct wkmap_aset_args args = {
.new_key = key,
.new_val = val,
};
st_update(w->table, (st_data_t)&key, wkmap_aset_replace, (st_data_t)&args);
RB_OBJ_WRITTEN(self, Qundef, key);
RB_OBJ_WRITTEN(self, Qundef, val);
return val;
}
Ordnet den gegebenen value dem gegebenen key zu
Die Referenz auf key ist schwach, sodass sie vom Garbage Collector eingesammelt werden kann, wenn keine andere Referenz auf key vorhanden ist.
Wenn der gegebene key existiert, wird sein Wert durch den gegebenen value ersetzt; die Reihenfolge wird nicht beeinflusst.
Source
static VALUE
wkmap_clear(VALUE self)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
st_foreach(w->table, wkmap_clear_i, (st_data_t)self);
st_clear(w->table);
return self;
}
Entfernt alle Zuordnungseinträge; gibt self zurück.
Source
static VALUE
wkmap_delete(VALUE self, VALUE key)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
VALUE orig_key = key;
st_data_t orig_key_data = (st_data_t)&orig_key;
st_data_t orig_val_data;
if (st_delete(w->table, &orig_key_data, &orig_val_data)) {
VALUE orig_val = (VALUE)orig_val_data;
rb_gc_remove_weak(self, (VALUE *)orig_key_data);
ruby_sized_xfree((VALUE *)orig_key_data, sizeof(VALUE));
return orig_val;
}
if (rb_block_given_p()) {
return rb_yield(key);
}
else {
return Qnil;
}
}
Löscht den Eintrag für den gegebenen key und gibt seinen zugeordneten Wert zurück.
Wenn kein Block gegeben ist und key gefunden wird, löscht es den Eintrag und gibt den zugeordneten Wert zurück.
m = ObjectSpace::WeakKeyMap.new key = "foo" # to hold reference to the key m[key] = 1 m.delete("foo") # => 1 m["foo"] # => nil
Wenn kein Block gegeben ist und key nicht gefunden wird, gibt es nil zurück.
Wenn ein Block gegeben ist und key gefunden wird, ignoriert es den Block, löscht den Eintrag und gibt den zugeordneten Wert zurück.
m = ObjectSpace::WeakKeyMap.new key = "foo" # to hold reference to the key m[key] = 2 m.delete("foo") { |key| raise 'Will never happen'} # => 2
Wenn ein Block gegeben ist und key nicht gefunden wird, wird key an den Block übergeben und der Rückgabewert des Blocks wird zurückgegeben.
m = ObjectSpace::WeakKeyMap.new m.delete("nosuch") { |key| "Key #{key} not found" } # => "Key nosuch not found"
Source
static VALUE
wkmap_getkey(VALUE self, VALUE key)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
st_data_t orig_key;
if (!st_get_key(w->table, (st_data_t)&key, &orig_key)) return Qnil;
return *(VALUE *)orig_key;
}
Gibt den existierenden gleichen Schlüssel zurück, wenn er existiert, andernfalls gibt es nil zurück.
Dies kann nützlich sein, um Caches zu implementieren, sodass nur eine Kopie eines bestimmten Objekts im gesamten Programm verwendet wird.
value = {amount: 1, currency: 'USD'} # Now if we put this object in a cache: cache = ObjectSpace::WeakKeyMap.new cache[value] = true # ...we can always extract from there and use the same object: copy = cache.getkey({amount: 1, currency: 'USD'}) copy.object_id == value.object_id #=> true
Source
static VALUE
wkmap_inspect(VALUE self)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
st_index_t n = st_table_size(w->table);
#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
const char * format = "#<%"PRIsVALUE":%p size=%lu>";
#else
const char * format = "#<%"PRIsVALUE":%p size=%llu>";
#endif
VALUE str = rb_sprintf(format, rb_class_name(CLASS_OF(self)), (void *)self, n);
return str;
}
Gibt einen neuen String mit Informationen über die Zuordnung zurück.
m = ObjectSpace::WeakKeyMap.new m[key] = value m.inspect # => "#<ObjectSpace::WeakKeyMap:0x00000001028dcba8 size=1>"
Source
static VALUE
wkmap_has_key(VALUE self, VALUE key)
{
return RBOOL(!UNDEF_P(wkmap_lookup(self, key)));
}
Gibt true zurück, wenn key ein Schlüssel in self ist, andernfalls false.