aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2016-04-20 16:08:47 +0200
committerXavier Noria <fxn@hashref.com>2016-04-20 16:28:54 +0200
commit697384df36a939e565b7c08725017d49dc83fe40 (patch)
tree688e284a508a243165ca154e3c41cecb7978fc29 /activesupport
parenta3c8a8ee9951969f31ef8fa5955e08513842cfaa (diff)
downloadrails-697384df36a939e565b7c08725017d49dc83fe40.tar.gz
rails-697384df36a939e565b7c08725017d49dc83fe40.tar.bz2
rails-697384df36a939e565b7c08725017d49dc83fe40.zip
~3.5x speedup of String#blank? for empty strings
See the rationale in the comment in this patch. To benchmark this I ran a number of variations, ultimately narrowing to require 'benchmark/ips' str = '' regexp = /\A[[:space:]]*\z/ Benchmark.ips do |x| x.report('regexp') { regexp === str } x.report('empty') { str.empty? || regexp === str } x.compare! end This benchmark has consistently reported speedups around 3.5x: Calculating ------------------------------------- regexp 69.197k i/100ms empty 115.468k i/100ms ------------------------------------------------- regexp 2. 6.3%) i/s - 13.839M empty 9. 8.8%) i/s - 47.804M Comparison: empty: 9642607.6 i/s regexp: 2768351.9 i/s - 3.48x slower Sometimes even reaching 4x. Running the same bechmark on strings of 10 or 100 characters (with whitespace or present) has shown a slowdown of just about 1.01/1.02. Marginal, we seem to have a worthwhile trade-off here.
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/core_ext/object/blank.rb7
1 files changed, 6 insertions, 1 deletions
diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb
index 039c50a4a2..71d411b6d6 100644
--- a/activesupport/lib/active_support/core_ext/object/blank.rb
+++ b/activesupport/lib/active_support/core_ext/object/blank.rb
@@ -112,7 +112,12 @@ class String
#
# @return [true, false]
def blank?
- BLANK_RE === self
+ # In practice, the majority of blank strings are empty. As of this writing
+ # checking for empty? is about 3.5x faster than matching against the regexp
+ # in MRI, so we call the predicate first, and then fallback.
+ #
+ # The penalty for blank strings with whitespace or present ones is marginal.
+ empty? || BLANK_RE === self
end
end