Class: ObjectSpace::WeakMap

Inherits:
Object show all
Includes:
Enumerable
Defined in:
weakmap.c,
weakmap.c

Overview

An ObjectSpace::WeakMap is a key-value map that holds weak references to its keys and values, so they can be garbage-collected when there are no more references left.

Keys in the map are compared by identity.

m = ObjectSpace::WeakMap.new
key1 = "foo"
val1 = Object.new
m[key1] = val1

key2 = "bar"
val2 = Object.new
m[key2] = val2

m[key1] #=> #<Object:0x0...>
m[key2] #=> #<Object:0x0...>

val1 = nil # remove the other reference to value
GC.start

m[key1] #=> nil
m.keys #=> ["bar"]

key2 = nil # remove the other reference to key
GC.start

m[key2] #=> nil
m.keys #=> []

(Note that GC.start is used here only for demonstrational purposes and might not always lead to demonstrated results.)

See also ObjectSpace::WeakKeyMap map class, which compares keys by value, and holds weak references only to the keys.

Instance Method Summary collapse

Methods included from Enumerable

#all?, #any?, #chain, #chunk, #chunk_while, #collect, #collect_concat, #compact, #count, #cycle, #detect, #drop, #drop_while, #each_cons, #each_entry, #each_slice, #each_with_index, #each_with_object, #entries, #filter, #filter_map, #find, #find_all, #find_index, #first, #flat_map, #grep, #grep_v, #group_by, #inject, #lazy, #map, #max, #max_by, #min, #min_by, #minmax, #minmax_by, #none?, #one?, #partition, #reduce, #reject, #reverse_each, #select, #slice_after, #slice_before, #slice_when, #sort, #sort_by, #sum, #take, #take_while, #tally, #to_a, #to_h, #uniq, #zip

Instance Method Details

#[](key) ⇒ Object

Returns the value associated with the given key if found.

If key is not found, returns nil.



514
515
516
517
518
519
# File 'weakmap.c', line 514

static VALUE
wmap_aref(VALUE self, VALUE key)
{
    VALUE obj = wmap_lookup(self, key);
    return !UNDEF_P(obj) ? obj : Qnil;
}

#[]=(key) ⇒ Object

Associates the given value with the given key.

If the given key exists, replaces its value with the given value; the ordering is not affected.



473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'weakmap.c', line 473

static VALUE
wmap_aset(VALUE self, VALUE key, VALUE val)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    VALUE pair[2] = { key, val };

    st_update(w->table, (st_data_t)pair, wmap_aset_replace, (st_data_t)pair);

    RB_OBJ_WRITTEN(self, Qundef, key);
    RB_OBJ_WRITTEN(self, Qundef, val);

    return Qnil;
}

#delete(key) ⇒ nil #delete(key) {|key| ... } ⇒ Object

Deletes the entry for the given key and returns its associated value.

If no block is given and key is found, deletes the entry and returns the associated value:

m = ObjectSpace::WeakMap.new
key = "foo"
m[key] = 1
m.delete(key) # => 1
m[key] # => nil

If no block is given and key is not found, returns nil.

If a block is given and key is found, ignores the block, deletes the entry, and returns the associated value:

m = ObjectSpace::WeakMap.new
key = "foo"
m[key] = 2
m.delete(key) { |key| raise 'Will never happen'} # => 2

If a block is given and key is not found, yields the key to the block and returns the block’s return value:

m = ObjectSpace::WeakMap.new
m.delete("nosuch") { |key| "Key #{key} not found" } # => "Key nosuch not found"

Overloads:

  • #delete(key) ⇒ nil

    Returns:

    • (nil)
  • #delete(key) {|key| ... } ⇒ Object

    Yields:

    • (key)

    Returns:



549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'weakmap.c', line 549

static VALUE
wmap_delete(VALUE self, VALUE key)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_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);
        rb_gc_remove_weak(self, (VALUE *)orig_val_data);

        struct weakmap_entry *entry = (struct weakmap_entry *)orig_key_data;
        ruby_sized_xfree(entry, sizeof(struct weakmap_entry));

        if (wmap_live_p(orig_val)) {
            return orig_val;
        }
    }

    if (rb_block_given_p()) {
        return rb_yield(key);
    }
    else {
        return Qnil;
    }
}

#each {|key, val| ... } ⇒ self

Iterates over keys and values. Note that unlike other collections, each without block isn’t supported.

Yields:

  • (key, val)

Returns:

  • (self)


319
320
321
322
323
324
325
326
327
328
# File 'weakmap.c', line 319

static VALUE
wmap_each(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    wmap_foreach(w, wmap_each_i, (st_data_t)0);

    return self;
}

#each_key {|key| ... } ⇒ self

Iterates over keys. Note that unlike other collections, each_key without block isn’t supported.

Yields:

  • (key)

Returns:

  • (self)


346
347
348
349
350
351
352
353
354
355
# File 'weakmap.c', line 346

static VALUE
wmap_each_key(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    wmap_foreach(w, wmap_each_key_i, (st_data_t)0);

    return self;
}

#each {|key, val| ... } ⇒ self

Iterates over keys and values. Note that unlike other collections, each without block isn’t supported.

Yields:

  • (key, val)

Returns:

  • (self)


319
320
321
322
323
324
325
326
327
328
# File 'weakmap.c', line 319

static VALUE
wmap_each(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    wmap_foreach(w, wmap_each_i, (st_data_t)0);

    return self;
}

#each_value {|val| ... } ⇒ self

Iterates over values. Note that unlike other collections, each_value without block isn’t supported.

Yields:

  • (val)

Returns:

  • (self)


373
374
375
376
377
378
379
380
381
382
# File 'weakmap.c', line 373

static VALUE
wmap_each_value(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    wmap_foreach(w, wmap_each_value_i, (st_data_t)0);

    return self;
}

#key?(key) ⇒ Boolean

Returns true if key is a key in self, otherwise false.

Returns:

  • (Boolean)


586
587
588
589
590
# File 'weakmap.c', line 586

static VALUE
wmap_has_key(VALUE self, VALUE key)
{
    return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
}

#inspectObject



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'weakmap.c', line 286

static VALUE
wmap_inspect(VALUE self)
{
    VALUE c = rb_class_name(CLASS_OF(self));
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    VALUE str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);

    wmap_foreach(w, wmap_inspect_i, (st_data_t)str);

    RSTRING_PTR(str)[0] = '#';
    rb_str_cat2(str, ">");

    return str;
}

#key?(key) ⇒ Boolean

Returns true if key is a key in self, otherwise false.

Returns:

  • (Boolean)


586
587
588
589
590
# File 'weakmap.c', line 586

static VALUE
wmap_has_key(VALUE self, VALUE key)
{
    return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
}

#keysObject

Returns a new Array containing all keys in the map.



401
402
403
404
405
406
407
408
409
410
411
# File 'weakmap.c', line 401

static VALUE
wmap_keys(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    VALUE ary = rb_ary_new();
    wmap_foreach(w, wmap_keys_i, (st_data_t)ary);

    return ary;
}

#sizeNumeric

Returns the number of referenced objects

Returns:



598
599
600
601
602
603
604
605
606
607
608
609
610
611
# File 'weakmap.c', line 598

static VALUE
wmap_size(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    st_index_t n = st_table_size(w->table);

#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
    return ULONG2NUM(n);
#else
    return ULL2NUM(n);
#endif
}

#key?(key) ⇒ Boolean

Returns true if key is a key in self, otherwise false.

Returns:

  • (Boolean)


586
587
588
589
590
# File 'weakmap.c', line 586

static VALUE
wmap_has_key(VALUE self, VALUE key)
{
    return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
}

#sizeNumeric

Returns the number of referenced objects

Returns:



598
599
600
601
602
603
604
605
606
607
608
609
610
611
# File 'weakmap.c', line 598

static VALUE
wmap_size(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    st_index_t n = st_table_size(w->table);

#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
    return ULONG2NUM(n);
#else
    return ULL2NUM(n);
#endif
}

#valuesObject

Returns a new Array containing all values in the map.



430
431
432
433
434
435
436
437
438
439
440
# File 'weakmap.c', line 430

static VALUE
wmap_values(VALUE self)
{
    struct weakmap *w;
    TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);

    VALUE ary = rb_ary_new();
    wmap_foreach(w, wmap_values_i, (st_data_t)ary);

    return ary;
}