Module: Weak::Map::WeakKeys

Defined in:
lib/weak/map/weak_keys.rb

Overview

This Weak::Map strategy targets Ruby < 3.3.0.

Its ObjectSpace::WeakMap uses weak keys and weak values so that either the key or the value can be independently garbage collected. If either of them vanishes, the entry is removed.

The ObjectSpace::WeakMap does not allow to explicitly delete entries. We emulate this by setting the garbage-collectible value of a deleted entry to a simple new object. This value will be garbage collected on the next GC run which will then remove the entry. When accessing elements, we delete and filter out these recently deleted entries.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.usable?Bool

Checks if this strategy is usable for the current Ruby version.

Returns:

  • (Bool)

    truethy for Ruby (aka. MRI, aka. YARV), falsey otherwise



30
31
32
# File 'lib/weak/map/weak_keys.rb', line 30

def self.usable?
  RUBY_ENGINE == "ruby"
end

Instance Method Details

#[](key) ⇒ Object

Note:

Set does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different strings are not considered equal, even if they may contain the same string content.

Returns the value associated with the given key, if found. If key is not found, returns the default value, i.e. the value returned by the default proc (if defined) or the default value (which is initially nil.).

Parameters:

  • key (Object)

    the key for the requested value

Returns:

  • (Object)

    the value associated with the given key, if found. If key is not found, returns the default value, i.e. the value returned by the default proc (if defined) or the default value (which is initially nil.)



35
36
37
38
# File 'lib/weak/map/weak_keys.rb', line 35

def [](key)
  raw_value = @map[key]
  missing?(raw_value) ? _default(key) : value!(raw_value)
end

#[]=(key, value) ⇒ Object

Note:

Set does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different strings are not considered equal, even if they may contain the same string content.

Associates the given value with the given key; returns value. If the given key exists, replaces its value with the given value.

Parameters:

  • key (Object)

    the key for the set key-value pair

  • value (Object)

    the value of the set key-value pair

Returns:

  • (Object)

    the given value



41
42
43
44
# File 'lib/weak/map/weak_keys.rb', line 41

def []=(key, value)
  @map[key] = value.nil? ? NIL : value
  value
end

#clearself

Removes all elements and returns self

Returns:

  • (self)


47
48
49
50
# File 'lib/weak/map/weak_keys.rb', line 47

def clear
  @map = ObjectSpace::WeakMap.new
  self
end

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

Note:

Set does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different strings are not considered equal, even if they may contain the same string content.

Deletes the key-value pair and returns the value from self whose key is equal to key. If the key is not found, it returns nil. If the optional block is given and the key is not found, pass in the key and return the result of the block.

Parameters:

  • key (Object)

    the key to delete

Yields:

  • (key)

Yield Parameters:

  • key (Object)

    the given key if it was not part of the map

Returns:

  • (Object, nil)

    the value associated with the given key, or the result of the optional block if given the key was not found, or nil if the key was not found and no block was given.



53
54
55
56
57
58
59
60
61
# File 'lib/weak/map/weak_keys.rb', line 53

def delete(key)
  raw_value = @map[key]
  if have?(raw_value)
    @map[key] = DeletedEntry.new
    value!(raw_value)
  elsif block_given?
    yield(key)
  end
end

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

Calls the given block once for each live key in self, passing the key as a parameter. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key)

    calls the given block once for each key in self

Yield Parameters:

  • key (Object)

    the key of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.



64
65
66
67
68
69
70
71
# File 'lib/weak/map/weak_keys.rb', line 64

def each_key
  return enum_for(__method__) { size } unless block_given?

  @map.keys.each do |key|
    yield key unless missing?(@map[key])
  end
  self
end

#each_pair {|key, value| ... } ⇒ self, Enumerator

Calls the given block once for each live key in self, passing the key and value as parameters. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key, value)

    calls the given block once for each key in self

Yield Parameters:

  • key (Object)

    the key of the current key-value pair

  • value (Object)

    the value of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.



74
75
76
77
78
79
80
81
82
# File 'lib/weak/map/weak_keys.rb', line 74

def each_pair
  return enum_for(__method__) { size } unless block_given?

  @map.keys.each do |key|
    raw_value = @map[key]
    yield [key, value!(raw_value)] unless missing?(raw_value)
  end
  self
end

#each_value {|value| ... } ⇒ self, Enumerator

Calls the given block once for each live key self, passing the live value associated with the key as a parameter. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (value)

    calls the given block once for each key in self

Yield Parameters:

  • value (Object)

    the value of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.



85
86
87
88
89
90
91
92
# File 'lib/weak/map/weak_keys.rb', line 85

def each_value
  return enum_for(__method__) { size } unless block_given?

  @map.values.each do |raw_value|
    yield value!(raw_value) unless missing?(raw_value)
  end
  self
end

#fetch(key, default = UNDEFINED) {|key| ... } ⇒ Object

Note:

Set does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different strings are not considered equal, even if they may contain the same string content.

Returns a value from the hash for the given key. If the key can't be found, there are several options: With no other arguments, it will raise a KeyError exception; if default is given, then that value will be returned; if the optional code block is specified, then it will be called and its result returned.

Parameters:

  • key (Object)

    the key for the requested value

  • default (Object) (defaults to: UNDEFINED)

    a value to return if there is no value at key in the hash

Yields:

  • (key)

    if no value was set at key, no default value was given, and a block was given, we call the block and return its value

Yield Parameters:

  • key (String)

    the given key

Returns:

  • (Object)

    the value for the given key if present in the map. If the key was not found, we return the default value or the value of the given block.

Raises:

  • (KeyError)

    if the key can not be found and no block or default value was provided



95
96
97
98
99
100
101
102
# File 'lib/weak/map/weak_keys.rb', line 95

def fetch(key, default = UNDEFINED, &block)
  raw_value = @map[key]
  if have?(raw_value)
    value!(raw_value)
  else
    _fetch_default(key, default, &block)
  end
end

#include?(key) ⇒ Bool

Note:

Set does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different strings are not considered equal, even if they may contain the same string content.

Returns true if the given key is included in self and has an associated live value, false otherwise.

Parameters:

  • key (Object)

    a possible key

Returns:

  • (Bool)

    true if the given key is included in self and has an associated live value, false otherwise



105
106
107
# File 'lib/weak/map/weak_keys.rb', line 105

def include?(key)
  have?(@map[key])
end

#keysArray

Note:

In contrast to a Hash, Weak::Maps do not necessarily retain insertion order.

Returns an Array containing all keys of the map for which we have a valid value. Keys with garbage-collected values are excluded.

Returns:

  • (Array)

    an Array containing all keys of the map for which we have a valid value. Keys with garbage-collected values are excluded.

See Also:



110
111
112
# File 'lib/weak/map/weak_keys.rb', line 110

def keys
  @map.keys.delete_if { |key| missing?(@map[key]) }
end

#pruneself

Cleanup data structures from the map to remove data associated with deleted or garbage collected keys and/or values. This method may be called automatically for some Weak::Map operations.

Returns:

  • (self)


115
116
117
# File 'lib/weak/map/weak_keys.rb', line 115

def prune
  self
end

#sizeInteger

Returns the number of live key-value pairs in self.

Returns:

  • (Integer)

    the number of live key-value pairs in self



120
121
122
# File 'lib/weak/map/weak_keys.rb', line 120

def size
  each_key.count
end

#valuesArray

Note:

In contrast to a Hash, Weak::Maps do not necessarily retain insertion order.

Returns an Array containing all values of the map for which we have a valid key. Values with garbage-collected keys are excluded.

Returns:

  • (Array)

    an Array containing all values of the map for which we have a valid key. Values with garbage-collected keys are excluded.

See Also:



125
126
127
128
129
130
131
# File 'lib/weak/map/weak_keys.rb', line 125

def values
  values = []
  @map.values.each do |raw_value|
    values << value!(raw_value) unless missing?(raw_value)
  end
  values
end