aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/weak_hash.rb41
-rw-r--r--activesupport/test/weak_hash_test.rb33
2 files changed, 74 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/weak_hash.rb b/activesupport/lib/active_support/weak_hash.rb
new file mode 100644
index 0000000000..d6096e606e
--- /dev/null
+++ b/activesupport/lib/active_support/weak_hash.rb
@@ -0,0 +1,41 @@
+module ActiveSupport
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
+ WeakHash = ::Weakling::WeakHash
+ else
+ class WeakHash
+ def initialize(cache = Hash.new)
+ @cache = cache
+ @key_map = {}
+ @rev_cache = Hash.new{|h,k| h[k] = {}}
+ @reclaim_value = lambda do |value_id|
+ if value = @rev_cache.delete(value_id)
+ value.each_key{|key| @cache.delete key}
+ end
+ end
+ end
+
+ def [](key)
+ value_id = @cache[key]
+ value_id && ObjectSpace._id2ref(value_id)
+ rescue RangeError
+ nil
+ end
+
+ def []=(key, value)
+ @rev_cache[value.object_id][key] = true
+ @cache[key] = value.object_id
+ @key_map[key.object_id] = key
+
+ ObjectSpace.define_finalizer(value, @reclaim_value)
+ end
+
+ def clear
+ @cache.clear
+ end
+
+ def delete(key)
+ @cache.delete(key)
+ end
+ end
+ end
+end
diff --git a/activesupport/test/weak_hash_test.rb b/activesupport/test/weak_hash_test.rb
new file mode 100644
index 0000000000..7d1620dc34
--- /dev/null
+++ b/activesupport/test/weak_hash_test.rb
@@ -0,0 +1,33 @@
+require 'abstract_unit'
+require 'active_support/weak_hash'
+
+class WeakHashTest < ActiveSupport::TestCase
+
+ def setup
+ @weak_hash = ActiveSupport::WeakHash.new
+ @str = "A";
+ @obj = Object.new
+ end
+
+ test "allows us to assign value, and return assigned value" do
+ a = @str; b = @obj
+ assert_equal @weak_hash[a] = b, b
+ end
+
+ test "should allow us to assign and read value" do
+ a = @str; b = @obj
+ assert_equal @weak_hash[a] = b, b
+ assert_equal @weak_hash[a], b
+ end
+
+ test "should use object_id to identify objects" do
+ a = Object.new
+ @weak_hash[a] = "b"
+ assert_nil @weak_hash[a.dup]
+ end
+
+ test "should find objects that have same hash" do
+ @weak_hash["a"] = "b"
+ assert_equal "b", @weak_hash["a"]
+ end
+end