Skip to content

Instantly share code, notes, and snippets.

@baweaver
Created August 2, 2021 04:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baweaver/c35262cdd31f583e014b7e47e8848664 to your computer and use it in GitHub Desktop.
Save baweaver/c35262cdd31f583e014b7e47e8848664 to your computer and use it in GitHub Desktop.
require 'benchmark/ips'
class TimeFilter
attr_reader :start, :finish
def initialize(start, finish)
@start = start
@finish = finish
end
def to_proc
proc do |value|
next false if start && value < start
next false if finish && value > finish
true
end
end
end
class TimeFilterLocal
attr_reader :start, :finish
def initialize(start, finish)
@start = start
@finish = finish
end
def to_proc
proc do |value|
start = self.start
finish = self.finish
next false if start && value < start
next false if finish && value > finish
true
end
end
end
class TimeFilterHoistedLocal
attr_reader :start, :finish
def initialize(start, finish)
@start = start
@finish = finish
end
def to_proc
start = self.start
finish = self.finish
proc do |value|
next false if start && value < start
next false if finish && value > finish
true
end
end
end
class TimeFilterProcBranch
attr_reader :start, :finish
def initialize(start, finish)
@start = start
@finish = finish
end
def to_proc
start = self.start
finish = self.finish
if start && finish
proc { |value| value >= start && value <= finish }
elsif start
proc { |value| value >= start }
elsif finish
proc { |value| value <= finish }
else
proc { |value| true }
end
end
end
class TimeFilterRanged
attr_reader :start, :finish, :range
def initialize(start, finish)
@start = start
@finish = finish
@range = Range.new(start, finish)
end
def to_proc
range = self.range
proc do |value|
range.include?(value)
end
end
end
SECONDS_IN_MINUTE = 60
SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE
SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR
BASE_TIME = Time.new(1990, 1, 1)
# Gets up to 2017-05-18 01:00:00 -0500
times = 10_000.times.map { |i| BASE_TIME + (i * SECONDS_IN_DAY) }
tf_original = TimeFilter.new(
Time.new(2000, 01, 01), nil
)
tf_local = TimeFilterLocal.new(
Time.new(2000, 01, 01), nil
)
tf_hoisted_local = TimeFilterHoistedLocal.new(
Time.new(2000, 01, 01), nil
)
tf_filtered_proc_branch = TimeFilterProcBranch.new(
Time.new(2000, 01, 01), nil
)
tf_filtered_range = TimeFilterRanged.new(
Time.new(2000, 01, 01), nil
)
Benchmark.ips do |bench|
bench.report("Original") { times.select(&tf_original) }
bench.report("Local") { times.select(&tf_local) }
bench.report("Hoisted Local") { times.select(&tf_hoisted_local) }
bench.report("Filtered Proc") { times.select(&tf_filtered_proc_branch) }
bench.report("Filtered Range") { times.select(&tf_filtered_range) }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment