Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added back Hash::Iterator because it's used in C-API.

  • Loading branch information...
commit 59c5b96c7c4cb8acb101d1b4364472d66f1807e7 1 parent a4f6089
@brixen brixen authored
View
34 kernel/common/hash.rb
@@ -29,6 +29,35 @@ def match?(key, key_hash)
end
end
+ # An external iterator that returns only entry chains from the
+ # Hash storage, never nil bins. While somewhat following the API
+ # of Enumerator, it is named Iterator because it does not provide
+ # <code>#each</code> and should not conflict with +Enumerator+ in
+ # MRI 1.8.7+. Returned by <code>Hash#to_iter</code>.
+
+ class Iterator
+ attr_reader :index
+
+ def initialize(entries, capacity)
+ @entries = entries
+ @capacity = capacity
+ @index = -1
+ end
+
+ # Returns the next object or +nil+.
+ def next(entry)
+ if entry and entry = entry.link
+ return entry
+ end
+
+ while (@index += 1) < @capacity
+ if entry = @entries[@index]
+ return entry
+ end
+ end
+ end
+ end
+
# Hash methods
attr_reader :size
@@ -646,6 +675,11 @@ def to_a
ary
end
+ # Returns an external iterator for the bins. See +Iterator+
+ def to_iter
+ Iterator.new @entries, @capacity
+ end
+
def to_hash
self
end
View
25 kernel/common/hash19.rb
@@ -84,6 +84,26 @@ def remove
end
end
+ # An external iterator that returns entries in insertion order. While
+ # somewhat following the API of Enumerator, it is named Iterator because it
+ # does not provide <code>#each</code> and should not conflict with
+ # +Enumerator+ in MRI 1.8.7+. Returned by <code>Hash#to_iter</code>.
+
+ class Iterator
+ def initialize(state)
+ @state = state
+ end
+
+ # Returns the next object or +nil+.
+ def next(entry)
+ if entry
+ return entry if entry = entry.next
+ else
+ return @state.head
+ end
+ end
+ end
+
# Hash methods
attr_reader :size
@@ -732,6 +752,11 @@ def to_a
ary
end
+ # Returns an external iterator for the bins. See +Iterator+
+ def to_iter
+ Iterator.new @state
+ end
+
def to_hash
self
end
View
24 kernel/common/hash_hamt.rb
@@ -290,6 +290,25 @@ def delete(key, key_hash)
end
end
+ # An external iterator that returns entries in insertion order. While
+ # somewhat following the API of Enumerator, it is named Iterator because it
+ # does not provide <code>#each</code> and should not conflict with
+ # +Enumerator+ in MRI 1.8.7+. Returned by <code>Hash#to_iter</code>.
+
+ class Iterator
+ def initialize(state)
+ @state = state
+ end
+
+ # Returns the next object or +nil+.
+ def next(entry)
+ if entry
+ return entry if entry = entry.next
+ else
+ return @state.head
+ end
+ end
+ end
# Hash methods
@@ -778,6 +797,11 @@ def to_a
ary
end
+ # Returns an external iterator for the bins. See +Iterator+
+ def to_iter
+ Iterator.new @state
+ end
+
def to_hash
self
end
View
23 spec/core/hash/iterator/index_spec.rb
@@ -0,0 +1,23 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+with_feature :hash_bucket do
+ describe "Hash::Iterator#index" do
+ ruby_version_is ""..."1.9" do
+ it "returns the index of the last object returned by #next" do
+ h = Hash.new
+ a = Hash::Bucket.new 1, 2, 3
+ b = Hash::Bucket.new 4, 5, 6
+ e = h.instance_variable_get :@entries
+ e[2] = a
+ e[4] = b
+
+ iter = h.to_iter
+
+ (entry = iter.next(entry)).should == a
+ (entry = iter.next(entry)).should == b
+
+ iter.index.should == 4
+ end
+ end
+ end
+end
View
16 spec/core/hash/iterator/new_spec.rb
@@ -0,0 +1,16 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+with_feature :hash_bucket do
+ describe "Hash::Iterator.new" do
+ ruby_version_is ""..."1.9" do
+ it "initializes the iterator" do
+ h = Hash[:a => 1, :b => 2]
+ entries = h.instance_variable_get :@entries
+ iter = h.to_iter
+ iter.instance_variable_get(:@entries).should == entries
+ iter.instance_variable_get(:@capacity).should == entries.size
+ iter.instance_variable_get(:@index).should == -1
+ end
+ end
+ end
+end
View
59 spec/core/hash/iterator/next_spec.rb
@@ -0,0 +1,59 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+with_feature :hash_bucket do
+ describe "Hash::Iterator#next" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ ruby_version_is ""..."1.9" do
+ it "returns each non-nil entry from the storage vector" do
+ h = Hash.new
+ a = Hash::Bucket.new 1, 2, 3
+ b = Hash::Bucket.new 4, 5, 6
+ c = Hash::Bucket.new 7, 8, 9
+ e = h.instance_variable_get :@entries
+ e[2] = a
+ e[4] = b
+ e[7] = c
+
+ iter = h.to_iter
+
+ while entry = iter.next(entry)
+ ScratchPad << entry
+ end
+ ScratchPad.recorded.should == [a, b, c]
+ end
+ end
+
+ ruby_version_is "1.9" do
+ it "returns each entry in the Hash" do
+ h = Hash[:a, 1, :b, 2, :c, 3]
+ iter = h.to_iter
+
+ while entry = iter.next(entry)
+ ScratchPad << entry.key
+ end
+ ScratchPad.recorded.should == [:a, :b, :c]
+ end
+ end
+ end
+end
+
+with_feature :hash_hamt do
+ describe "Hash::Iterator#next" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ it "returns each entry in the Hash" do
+ h = Hash[:a, 1, :b, 2, :c, 3]
+ iter = h.to_iter
+
+ while entry = iter.next(entry)
+ ScratchPad << entry.key
+ end
+ ScratchPad.recorded.should == [:a, :b, :c]
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.