Skip to content

Commit

Permalink
Merge pull request #320 from rails/schneems/digest-speed
Browse files Browse the repository at this point in the history
Speed up digest with recursive hash
  • Loading branch information
schneems committed Jun 21, 2016
2 parents 88fca20 + 94a1207 commit ab6b0a5
Showing 1 changed file with 45 additions and 39 deletions.
84 changes: 45 additions & 39 deletions lib/sprockets/digest_utils.rb
Expand Up @@ -35,6 +35,50 @@ def detect_digest_class(bytes)
DIGEST_SIZES[bytes.bytesize]
end

ADD_VALUE_TO_DIGEST = {
String => ->(val, digest) { digest << val },
FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
NilClass => ->(val, digest) { digest << 'NilClass'.freeze },

Symbol => ->(val, digest) {
digest << 'Symbol'.freeze
digest << val.to_s
},
Fixnum => ->(val, digest) {
digest << 'Fixnum'.freeze
digest << val.to_s
},
Bignum => ->(val, digest) {
digest << 'Bignum'.freeze
digest << val.to_s
},
Array => ->(val, digest) {
digest << 'Array'.freeze
val.each do |element|
ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
end
},
Hash => ->(val, digest) {
digest << 'Hash'.freeze
val.sort.each do |array|
ADD_VALUE_TO_DIGEST[Array].call(array, digest)
end
},
Set => ->(val, digest) {
digest << 'Set'.freeze
ADD_VALUE_TO_DIGEST[Array].call(val.to_a, digest)
},
Encoding => ->(val, digest) {
digest << 'Encoding'.freeze
digest << val.name
},
}
ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
raise TypeError, "couldn't digest #{ val }"
}
private_constant :ADD_VALUE_TO_DIGEST

# Internal: Generate a hexdigest for a nested JSON serializable object.
#
# This is used for generating cache keys, so its pretty important its
Expand All @@ -45,46 +89,8 @@ def detect_digest_class(bytes)
# Returns a String digest of the object.
def digest(obj)
digest = digest_class.new
queue = [obj]

while queue.length > 0
obj = queue.shift
klass = obj.class

if klass == String
digest << obj
elsif klass == Symbol
digest << 'Symbol'
digest << obj.to_s
elsif klass == Fixnum
digest << 'Fixnum'
digest << obj.to_s
elsif klass == Bignum
digest << 'Bignum'
digest << obj.to_s
elsif klass == TrueClass
digest << 'TrueClass'
elsif klass == FalseClass
digest << 'FalseClass'
elsif klass == NilClass
digest << 'NilClass'.freeze
elsif klass == Array
digest << 'Array'
queue.concat(obj)
elsif klass == Hash
digest << 'Hash'
queue.concat(obj.sort)
elsif klass == Set
digest << 'Set'
queue.concat(obj.to_a)
elsif klass == Encoding
digest << 'Encoding'
digest << obj.name
else
raise TypeError, "couldn't digest #{klass}"
end
end

ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
digest.digest
end

Expand Down

0 comments on commit ab6b0a5

Please sign in to comment.