Skip to content

Commit

Permalink
Rework ActiveSupport::OrderedHash to make lookups faster
Browse files Browse the repository at this point in the history
[rails#1352 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information
fcheung authored and jeremy committed Dec 10, 2008
1 parent 014b799 commit 355f41d
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 38 deletions.
5 changes: 3 additions & 2 deletions activerecord/test/cases/calculations_test.rb
Expand Up @@ -171,8 +171,9 @@ def test_should_group_by_association_with_non_numeric_foreign_key
Account.expects(:columns).at_least_once.returns([column])

c = Account.count(:all, :group => :firm)
assert_equal Firm, c.first.first.class
assert_equal 1, c.first.last
first_key = c.keys.first
assert_equal Firm, first_key.class
assert_equal 1, c[first_key]
end
end

Expand Down
59 changes: 23 additions & 36 deletions activesupport/lib/active_support/ordered_hash.rb
Expand Up @@ -4,62 +4,49 @@ module ActiveSupport
if RUBY_VERSION >= '1.9'
OrderedHash = ::Hash
else
class OrderedHash < Array #:nodoc:
def []=(key, value)
if pair = assoc(key)
pair.pop
pair << value
else
self << [key, value]
end
value
class OrderedHash < Hash #:nodoc:
def initialize(*args, &block)
super
@keys = []
end

def [](key)
pair = assoc(key)
pair ? pair.last : nil
def []=(key, value)
if !has_key?(key)
@keys << key
end
super
end

def delete(key)
pair = assoc(key)
pair ? array_index = index(pair) : nil
array_index ? delete_at(array_index).last : nil
array_index = has_key?(key) && index(key)
if array_index
@keys.delete_at(array_index)
end
super
end

def keys
collect { |key, value| key }
@keys
end

def values
collect { |key, value| value }
@keys.collect { |key| self[key] }
end

def to_hash
returning({}) do |hash|
each { |array| hash[array[0]] = array[1] }
end
end

def has_key?(k)
!assoc(k).nil?
end

alias_method :key?, :has_key?
alias_method :include?, :has_key?
alias_method :member?, :has_key?

def has_value?(v)
any? { |key, value| value == v }
Hash.new(self)
end

alias_method :value?, :has_value?

def each_key
each { |key, value| yield key }
@keys.each { |key| yield key }
end

def each_value
each { |key, value| yield value }
@keys.each { |key| yield self[key]}
end

def each
keys.each {|key| yield [key, self[key]]}
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions activesupport/test/ordered_hash_test.rb
Expand Up @@ -73,4 +73,14 @@ def test_each_value
@ordered_hash.each_value { |v| values << v }
assert_equal @values, values
end

def test_each
values = []
@ordered_hash.each {|key, value| values << value}
assert_equal @values, values
end

def test_each_with_index
@ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair}
end
end

0 comments on commit 355f41d

Please sign in to comment.