wref 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ class Wref::Implementations::IdClassUnique
2
+ def initialize(object)
3
+ @id = object.__id__
4
+ @class_name = object.class.name.to_sym
5
+ ObjectSpace.define_finalizer(object, method(:destroy))
6
+ @unique_id = object.__wref_unique_id__ if object.respond_to?(:__wref_unique_id__)
7
+ end
8
+
9
+ def get!
10
+ object = get
11
+ raise ::Wref::Recycled unless object
12
+ return object
13
+ end
14
+
15
+ def get
16
+ return nil if !@class_name || !@id
17
+ object = ObjectSpace._id2ref(@id)
18
+
19
+ #Some times this class-name will be nil for some reason - knj
20
+ object_class_name = object.class.name
21
+
22
+ if !object_class_name || @class_name != object_class_name.to_sym || @id != object.__id__
23
+ destroy
24
+ return nil
25
+ end
26
+
27
+ if @unique_id
28
+ destroy
29
+ return nil if !object.respond_to?(:__wref_unique_id__) || object.__wref_unique_id__ != @unique_id
30
+ end
31
+
32
+ return object
33
+ end
34
+
35
+ def alive?
36
+ if get
37
+ return true
38
+ else
39
+ return false
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def destroy(*args)
46
+ @id = nil
47
+ @class_name = nil
48
+ @unique_id = nil
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ class Wref::Implementations::JavaWeakReference
2
+ def initialize(object)
3
+ require "java"
4
+ @weakref = java.lang.ref.WeakReference.new(object)
5
+ end
6
+
7
+ def get
8
+ return @weakref.get
9
+ end
10
+
11
+ def get!
12
+ object = @weakref.get
13
+ raise Wref::Recycled if object == nil
14
+ return object
15
+ end
16
+
17
+ def alive?
18
+ object = @weakref.get
19
+
20
+ if object == nil
21
+ return false
22
+ else
23
+ return true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ class Wref::Implementations::Ref
2
+ def initialize(object)
3
+ require "ref"
4
+ @ref = ::Ref::WeakReference.new(object)
5
+ end
6
+
7
+ def get
8
+ @ref.object
9
+ end
10
+
11
+ def get!
12
+ object = @ref.object
13
+ raise Wref::Recycled unless object
14
+ return object
15
+ end
16
+
17
+ def alive?
18
+ if @ref.object
19
+ return true
20
+ else
21
+ return false
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ class Wref::Implementations::WeakRef
2
+ def initialize(object)
3
+ require "weakref"
4
+ @id = object.__id__
5
+ @class_name = object.class.name.to_sym
6
+ @weak_ref = ::WeakRef.new(object)
7
+ ObjectSpace.define_finalizer(object, method(:destroy))
8
+ end
9
+
10
+ def get
11
+ return nil unless @id
12
+
13
+ begin
14
+ object = @weak_ref.__getobj__
15
+ rescue WeakRef::RefError
16
+ destroy
17
+ return nil
18
+ end
19
+
20
+ object_class_name = object.class.name
21
+
22
+ if !object_class_name || @class_name != object_class_name.to_sym || @id != object.__id__
23
+ destroy
24
+ return nil
25
+ end
26
+
27
+ return object
28
+ end
29
+
30
+ def get!
31
+ if object = get
32
+ return object
33
+ else
34
+ raise Wref::Recycled
35
+ end
36
+ end
37
+
38
+ def alive?
39
+ if @weak_ref.weakref_alive? && get
40
+ return true
41
+ else
42
+ return false
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def destroy(*args)
49
+ @id = nil
50
+ @class_name = nil
51
+ @unique_id = nil
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ class Wref::Implementations::Weakling
2
+ def initialize(object)
3
+ require "weakling"
4
+ @weak_ref = ::Weakling::WeakRef.new(object)
5
+ end
6
+
7
+ def get
8
+ begin
9
+ @weak_ref.get
10
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
11
+ return nil
12
+ end
13
+ end
14
+
15
+ def get!
16
+ begin
17
+ @weak_ref.get
18
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
19
+ raise Wref::Recycled
20
+ end
21
+ end
22
+
23
+ def alive?
24
+ begin
25
+ @weak_ref.get
26
+ return true
27
+ rescue ::WeakRef::RefError, ::Java::JavaLang::NullPointerException
28
+ return false
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,175 @@
1
+ #A weak hash-map.
2
+ #===Examples
3
+ # map = Wref::Map.new
4
+ # map[1] = obj
5
+ # obj = nil
6
+ #
7
+ # sleep 0.5
8
+ #
9
+ # begin
10
+ # obj = map[1]
11
+ # print "Object still exists in memory."
12
+ # rescue Wref::Recycled
13
+ # print "Object has been garbage-collected."
14
+ # end
15
+ #
16
+ # obj = map.get(1)
17
+ # print "Object still exists in memory." if obj
18
+ class Wref::Map
19
+ def initialize(args = {})
20
+ require "monitor"
21
+
22
+ @map = {}
23
+ @mutex = Monitor.new
24
+ @impl = args[:impl]
25
+ end
26
+
27
+ #Sets a new object in the map with a given ID.
28
+ def set(id, obj)
29
+ wref = Wref.new(obj, impl: @impl)
30
+
31
+ @mutex.synchronize do
32
+ @map[id] = wref
33
+ end
34
+
35
+ return nil
36
+ end
37
+
38
+ #Returns an object by ID or raises a RefError.
39
+ #===Examples
40
+ # begin
41
+ # obj = map.get!(1)
42
+ # print "Object still exists in memory."
43
+ # rescue Wref::Recycled
44
+ # print "Object has been garbage-collected."
45
+ # end
46
+ def get!(id)
47
+ wref = nil
48
+ @mutex.synchronize do
49
+ raise Wref::Recycled unless @map.key?(id)
50
+ wref = @map[id]
51
+ end
52
+
53
+ if object = wref.get
54
+ return object
55
+ else
56
+ delete(id)
57
+ raise Wref::Recycled
58
+ end
59
+ end
60
+
61
+ #The same as 'get!' but returns nil instead of WeakRef-error. This can be used to avoid writing lots of code.
62
+ #===Examples
63
+ # obj = map.get(1)
64
+ # print "Object still exists in memory." if obj
65
+ def get(id)
66
+ begin
67
+ return get!(id)
68
+ rescue Wref::Recycled
69
+ return nil
70
+ end
71
+ end
72
+
73
+ #Scans the whole map and removes dead references. After the implementation of automatic clean-up by using ObjectSpace.define_finalizer, there should be no reason to call this method.
74
+ def clean
75
+ keys = nil
76
+ @mutex.synchronize do
77
+ keys = @map.keys
78
+ end
79
+
80
+ keys.each do |key|
81
+ begin
82
+ get(key) #this will remove the key if the object no longer exists.
83
+ rescue Wref::Recycled
84
+ #ignore.
85
+ end
86
+ end
87
+
88
+ return nil
89
+ end
90
+
91
+ #Returns true if a given key exists and the object it holds is alive.
92
+ def valid?(key)
93
+ @mutex.synchronize do
94
+ return false unless @map.key?(key)
95
+ end
96
+
97
+ begin
98
+ @map[key].get
99
+ return true
100
+ rescue Wref::Recycled
101
+ return false
102
+ end
103
+ end
104
+
105
+ #Returns true if the given key exists in the hash.
106
+ #===Examples
107
+ # print "Key exists but we dont know if the value has been garbage-collected." if map.key?(1)
108
+ def key?(key)
109
+ @mutex.synchronize do
110
+ if @map.key?(key) && get(key)
111
+ return true
112
+ else
113
+ return false
114
+ end
115
+ end
116
+ end
117
+
118
+ #Returns the length of the hash. This may not be true since invalid objects is also counted.
119
+ def length
120
+ @mutex.synchronize do
121
+ return @map.length
122
+ end
123
+ end
124
+
125
+ #Cleans the hash and returns the length. This is slower but more accurate than the ordinary length that just returns the hash-length.
126
+ def length_valid
127
+ clean
128
+ return length
129
+ end
130
+
131
+ #Deletes a key in the hash.
132
+ def delete(key)
133
+ @mutex.synchronize do
134
+ wref = @map[key]
135
+ object = @map.delete(key)
136
+
137
+ if object
138
+ return object.get
139
+ else
140
+ return nil
141
+ end
142
+ end
143
+ end
144
+
145
+ #Iterates over every valid object in the weak map.
146
+ #===Examples
147
+ # map.each do |obj|
148
+ # puts "Object alive: #{obj}"
149
+ # end
150
+ def each(&block)
151
+ enum = Enumerator.new do |yielder|
152
+ ids = nil
153
+ @mutex.synchronize do
154
+ ids = @map.keys
155
+ end
156
+
157
+ ids.each do |id|
158
+ if obj = get(id)
159
+ yielder << [id, obj]
160
+ end
161
+ end
162
+ end
163
+
164
+ if block
165
+ enum.each(&block)
166
+ else
167
+ return enum
168
+ end
169
+ end
170
+
171
+ #Make it hash-compatible.
172
+ alias has_key? key?
173
+ alias [] get
174
+ alias []= set
175
+ end
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - ruby-2.1-head
5
+ - ruby-2.0-head
6
+ - ruby-1.9.3-head
7
+ - ruby-1.9.2-head
8
+ - jruby-head
9
+ script:
10
+ - CODECLIMATE_REPO_TOKEN=23d002ad9b86687a067e6bbc81320cd979ffad756d1be69ca4e24c1038ee19a6 bundle exec rspec
11
+ notifications:
12
+ email: false
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::IdClassUnique do
4
+ it_should_behave_like "wref" unless RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" unless RUBY_ENGINE == "jruby"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::JavaWeakReference do
4
+ it_should_behave_like "wref" if RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" if RUBY_ENGINE == "jruby"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::Ref do
4
+ it_should_behave_like "wref"
5
+ it_should_behave_like "map"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::WeakRef do
4
+ it_should_behave_like "wref"
5
+ it_should_behave_like "map"
6
+ end
@@ -0,0 +1,6 @@
1
+ require "spec_helper"
2
+
3
+ describe Wref::Implementations::Weakling do
4
+ it_should_behave_like "wref" if RUBY_ENGINE == "jruby"
5
+ it_should_behave_like "map" if RUBY_ENGINE == "jruby"
6
+ end
@@ -1,12 +1,19 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
1
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'rspec'
4
- require 'wref'
6
+ require "rspec"
7
+ require "wref"
8
+ require "weakling" if RUBY_ENGINE == "jruby"
9
+ require "ref"
5
10
 
6
11
  # Requires supporting files with custom matchers and macros, etc,
7
12
  # in ./support/ and its subdirectories.
8
13
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
14
 
10
15
  RSpec.configure do |config|
11
-
16
+ config.expect_with :rspec do |c|
17
+ c.syntax = [:should, :expect]
18
+ end
12
19
  end
@@ -0,0 +1,33 @@
1
+ module GarbageCollectorHelper
2
+ def force_garbage_collect
3
+ GC.enable
4
+
5
+ sleep 0.01
6
+
7
+ if RUBY_ENGINE == "jruby"
8
+ java.lang.System.gc
9
+ else
10
+ if RUBY_VERSION.start_with?("2")
11
+ GC.start(full_mark: true, immediate_sweep: true)
12
+ else
13
+ GC.start
14
+ end
15
+ end
16
+
17
+ sleep 0.01
18
+
19
+ GC.disable
20
+ end
21
+
22
+ def force_garbage_collection
23
+ force_garbage_collect
24
+
25
+ 10000.times do
26
+ some_str = User.new("User #{Digest::MD5.hexdigest(Time.now.to_f.to_s)}")
27
+ weak_ref = described_class.new(some_str)
28
+ some_str = nil
29
+ end
30
+
31
+ force_garbage_collect
32
+ end
33
+ end