Skip to content

Loading…

String concat #20

Closed
wants to merge 2 commits into from

2 participants

@kbrock

Didn't really produce the savings I was expecting.
Basically, it is the same thing.

So don't accept this request.

But it is an alternative view of the problem.

So wanted to forward along.

@jeremyw jeremyw closed this
@kbrock kbrock commented on the diff
lib/stamp/emitters/two_digit.rb
((6 lines not shown))
value = modify(target.send(field))
- '%2.2d' % value
+ out << (value < 10 ? '0' : '') << value.to_s
@kbrock
kbrock added a note

yea, this should be:

out << '0' if value < 10
out << value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@kbrock

@jeremyw any thoughts of this?

Funny. I was just about to suggest this PR again.
I did notice that the join code was converted to an each and <<. So most of the speed improvement is probably already realized.

Locally my raw benchmarks seem to suggest this could get 10% speed improvement. Mostly around the out << '0' use case.

If you are open to this idea, I'll rebase and play. Otherwise, if you really don't like it, I'll let live and probably ask again in another year or so.

@jeremyw jeremyw commented on the diff
lib/stamp/emitters/composite.rb
@@ -7,12 +7,9 @@ def initialize
@emitters = []
end
- def format(target)
- # NOTE using #each to build string because benchmarking shows
- # that it's ~20% faster than .map.join('')
- result = ''
- @emitters.each { |e| result << e.format(target).to_s }
- result
+ def format(out, target)
@jeremyw Owner
jeremyw added a note

I'm not sure why this is better. It seems like it just distributes string-building responsibility to the emitters.

@kbrock
kbrock added a note

yes. that is all it is.
In the cases where you want to output more than 1 string, it ends up being quicker to lambda |result, target| result << str1 << str2 } than result << lambda { |target| str1 + str2 }.

Granted it is probably 10% in trivial benchmarks, but hey. that is something right?
(well, if you think it is much uglier, than that probably doesn't warrant the change)

It is hard to benchmark across these changes. I like benchmark-ips, but not sure how to do it across sweeping changes like this. Only can do it with lambdas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 15, 2012
  1. @kbrock
  2. @kbrock

    playing with different ways to improve timing.

    kbrock committed
    looks like string concat ( << ) saves
View
2 lib/stamp.rb
@@ -28,7 +28,7 @@ module Stamp
# @example
# Date.new(2012, 12, 21).stamp("Jan 1, 1999") #=> "Dec 21, 2012"
def stamp(example)
- memoize_stamp_emitters(example).format(self)
+ memoize_stamp_emitters(example).format('', self)
end
alias :stamp_like :stamp
alias :format_like :stamp
View
4 lib/stamp/emitters/am_pm.rb
@@ -10,8 +10,8 @@ def initialize(&block)
@modifier = block
end
- def format(target)
- modify(target.hour < 12 ? AM : PM)
+ def format(out, target)
+ out << modify(target.hour < 12 ? AM : PM)
end
def field
View
9 lib/stamp/emitters/composite.rb
@@ -7,12 +7,9 @@ def initialize
@emitters = []
end
- def format(target)
- # NOTE using #each to build string because benchmarking shows
- # that it's ~20% faster than .map.join('')
- result = ''
- @emitters.each { |e| result << e.format(target).to_s }
- result
+ def format(out, target)
@jeremyw Owner
jeremyw added a note

I'm not sure why this is better. It seems like it just distributes string-building responsibility to the emitters.

@kbrock
kbrock added a note

yes. that is all it is.
In the cases where you want to output more than 1 string, it ends up being quicker to lambda |result, target| result << str1 << str2 } than result << lambda { |target| str1 + str2 }.

Granted it is probably 10% in trivial benchmarks, but hey. that is something right?
(well, if you think it is much uglier, than that probably doesn't warrant the change)

It is hard to benchmark across these changes. I like benchmark-ips, but not sure how to do it across sweeping changes like this. Only can do it with lambdas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ @emitters.each { |e| e.format(out, target) }
+ out
end
def <<(emitter)
View
4 lib/stamp/emitters/delegate.rb
@@ -11,8 +11,8 @@ def initialize(field, &block)
@modifier = block
end
- def format(target)
- modify(target.send(field))
+ def format(out, target)
+ out << modify(target.send(field).to_s)
end
end
end
View
4 lib/stamp/emitters/lookup.rb
@@ -11,8 +11,8 @@ def initialize(field, lookup=nil)
@lookup = lookup
end
- def format(target)
- lookup(target.send(field))
+ def format(out, target)
+ out << lookup(target.send(field))
end
def lookup(value)
View
4 lib/stamp/emitters/numeric_emitter.rb
@@ -8,8 +8,8 @@ def initialize(field)
@field = field
end
- def format(target)
- target.send(field)
+ def format(out, target)
+ out << target.send(field)
end
end
end
View
4 lib/stamp/emitters/ordinal.rb
@@ -8,8 +8,8 @@ def initialize(field)
@field = field
end
- def format(target)
- ordinalize(target.send(field))
+ def format(out, target)
+ out << ordinalize(target.send(field))
end
# Cribbed from ActiveSupport::Inflector
View
4 lib/stamp/emitters/string.rb
@@ -7,8 +7,8 @@ def initialize(value)
@value = value
end
- def format(target)
- value
+ def format(out, target)
+ out << value.to_s
end
def <<(emitter)
View
4 lib/stamp/emitters/two_digit.rb
@@ -13,9 +13,9 @@ def initialize(field, &block)
@modifier = block
end
- def format(target)
+ def format(out, target)
value = modify(target.send(field))
- '%2.2d' % value
+ out << (value < 10 ? '0' : '') << value.to_s
@kbrock
kbrock added a note

yea, this should be:

out << '0' if value < 10
out << value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
end
end
end
Something went wrong with that request. Please try again.