Skip to content

Commit

Permalink
Removing and reasigning of complex keys fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
swistak committed Jul 18, 2010
1 parent 7ca7de3 commit 96d3486
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 16 deletions.
6 changes: 1 addition & 5 deletions lib/weakling/weak_hash.rb
Expand Up @@ -32,17 +32,13 @@ def initialize
@rev_hash_map = Hash.new
end

def delete(key)
@reclaim_key.call(key.object_id)
end

def clear
[@key_to_value, @value_to_keys, @hash_map, @rev_hash_map].each{|h| h.clear}

self
end

def _clean?
def empty?
@key_to_value.empty? &&
@value_to_keys.empty? &&
@hash_map.empty? &&
Expand Down
20 changes: 14 additions & 6 deletions lib/weakling/weak_hash/jruby_core.rb
Expand Up @@ -54,16 +54,13 @@ def [](key)
end

def []=(key, value)
# If key was already occupied by another value, we must first remove old key
delete(key)

_cleanup
key_ref = IdWeakRef.new(key, @key_queue)
value_ref = IdWeakRef.new(value, @value_queue)

# If key was already occupied by another value, we must first remove key
# from reverse _value_ => _key_ map
if old_value_ref = @key_to_value[key_ref.id]
@value_to_keys[old_value_ref.id].delete(key_ref.id)
end

# Assigns value reference to key, and vice-versa
@key_to_value[key_ref.id] = value_ref
@value_to_keys[value_ref.id][key_ref.id] = key_ref
Expand All @@ -75,6 +72,17 @@ def []=(key, value)
value
end

def delete(key)
if @hash_map.has_key?(key.hash)
@hash_map[key.hash].any? do |k_id, key_ref|
hkey = key_ref.get rescue nil
@reclaim_key.call(k_id) if hkey == key
end
end

nil
end

def each
_cleanup

Expand Down
15 changes: 12 additions & 3 deletions lib/weakling/weak_hash/mri_core.rb
Expand Up @@ -38,9 +38,7 @@ def [](key)
end

def []=(key, value)
if v_id = @key_to_value[key.object_id]
@value_to_keys[v_id].delete(key.object_id)
end
delete(key)

@key_to_value[key.object_id] = value.object_id

Expand All @@ -57,6 +55,17 @@ def []=(key, value)

value
end

def delete(key)
if @hash_map.has_key?(key.hash)
@hash_map[key.hash].keys.each do |k_id|
hkey = ObjectSpace._id2ref(k_id) rescue nil
@reclaim_key.call(k_id) if hkey == key
end
end

nil
end

def each
@key_to_value.each do |key_id, value_id|
Expand Down
30 changes: 29 additions & 1 deletion spec/weakhash_spec.rb
Expand Up @@ -17,6 +17,16 @@ def force_gc_cleanup
sleep 0.5 # Give GC a little time to do the magick
end

class TestStruct < Struct.new(:foo, :bar)
def <=>(other)
self.foo <=> other.foo
end

def ==(other)
self.foo == other.foo && self.bar == other.bar
end
end

# Looks like there's a strange bug in MRI 1.8.7 and 1.9.1 last value assigned to hash
# Is somehow bound and not collected - I'm not sure why, it looks like scoping
# issue with blocks and enumerators (adding nil at the end of the block solved
Expand All @@ -26,7 +36,7 @@ def force_gc_cleanup
# So for test purposes we're ignoring that one item in hash
Spec::Matchers.define :be_almost_empty do
match do |actual|
actual._clean? ||
actual.empty? ||
%w{key_to_value value_to_keys hash_map rev_hash_map}.all?{|k|
actual.instance_variable_get("@#{k}").length <= 1
}
Expand Down Expand Up @@ -89,6 +99,24 @@ def force_gc_cleanup
@weak_hash.to_a.sort.should == result
end

it "should allow for assigning complex keys and values" do
@weak_hash[["Test", 1]] = TestStruct.new("raz", "dwa")
@weak_hash[["Foo", 2]] = a = TestStruct.new("uno", "duo")
@weak_hash[["Test", 1]] = b = TestStruct.new("ichi", "ni")

@weak_hash.map{|k,v| [k,v]}.sort.should == [[["Foo", 2], a], [["Test", 1], b]]
end

it "Should allow removal of keys" do
@weak_hash[["Test", 1]] = TestStruct.new("raz", "dwa")
@weak_hash[["Foo", 2]] = a = TestStruct.new("uno", "duo")

@weak_hash.delete(["Test", 1])
@weak_hash.delete(["Foo", 2])

@weak_hash.empty?
end

it "should allow iteration" do
result = {}
(1..10).map do |x|
Expand Down
2 changes: 1 addition & 1 deletion weakling.gemspec
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = %q{weakling}
s.version = "0.1.5"
s.version = "0.1.6"
s.authors = ["Charles Oliver Nutter", "Marcin Raczkowski"]
s.date = Time.now.strftime('%Y-%m-%d')
s.description = "A modified WeakRef impl for JRuby plus some weakref-related tools"
Expand Down

0 comments on commit 96d3486

Please sign in to comment.