diff --git a/lib/stupidedi/reader/pointer.rb b/lib/stupidedi/reader/pointer.rb index 611fbb428..d6077ce8c 100644 --- a/lib/stupidedi/reader/pointer.rb +++ b/lib/stupidedi/reader/pointer.rb @@ -338,6 +338,9 @@ def inspect # This operation typically allocates memory and copies part of @storage, # so this is avoided as much as possible. # + # Unless the optional parameter `always_allocate` is `true`, then the + # return value may be `#frozen?` in some cases. + # # @return [S] def reify(always_allocate = false) if @storage.frozen? \ diff --git a/lib/stupidedi/reader/substring.rb b/lib/stupidedi/reader/substring.rb index 75ef87606..950f910f0 100644 --- a/lib/stupidedi/reader/substring.rb +++ b/lib/stupidedi/reader/substring.rb @@ -177,6 +177,7 @@ def count(other) # substring pointer. # # @return [self] + Z = "abc" def <<(other) case other when self.class @@ -185,7 +186,7 @@ def <<(other) @length += other.length elsif not @storage.frozen? # Surely no one will notice if we destructively update @storage - @storage[@offset + @length, @storage.length - @offset - @length] = other + @storage[@offset + @length, @storage.length - @offset - @length] = other.reify @length += other.length else # Other pointers are sharing our storage. We need to make our own diff --git a/lib/stupidedi/reader/tokenizer.rb b/lib/stupidedi/reader/tokenizer.rb index b1e0c0d45..ad1f7ec7f 100644 --- a/lib/stupidedi/reader/tokenizer.rb +++ b/lib/stupidedi/reader/tokenizer.rb @@ -528,7 +528,7 @@ def _update_state(segment_tok, config) gscode = version.try(:slice, 0, 6) # GS01: Functional Identifier Code - fgcode = segment_tok.element_toks.at(0).try(:value) + # fgcode = segment_tok.element_toks.at(0).try(:value) if config.functional_group.defined_at?(gscode) envelope_def = config.functional_group.at(gscode) diff --git a/lib/stupidedi/ruby/string.rb b/lib/stupidedi/ruby/string.rb index ac590f42f..ba460dfa2 100644 --- a/lib/stupidedi/ruby/string.rb +++ b/lib/stupidedi/ruby/string.rb @@ -90,6 +90,7 @@ def match?(pattern, pos=nil) if pos.nil? !!(self =~ pattern) else + # NOTE: Regexp#match allocates a MatchData, String#match does not !!match(pattern, pos) end end diff --git a/spec/lib/stupidedi/reader/native_ext_spec.rb b/spec/lib/stupidedi/reader/native_ext_spec.rb index 58467c53c..cc69f7a7d 100644 --- a/spec/lib/stupidedi/reader/native_ext_spec.rb +++ b/spec/lib/stupidedi/reader/native_ext_spec.rb @@ -171,7 +171,7 @@ expect(extend_language).to be_graphic(encoding: e) end - if n = e[/iso-8859-(\d+)/, 1].try{|n| Integer(n) } + if n = e[/iso-8859-(\d+)/, 1].try{|m| Integer(m) } it "identifies all graphic characters" do bytes = iso_8859_table.reject{|_, no| no.include?(n) }.keys string = bytes.sort.map(&:chr).join.force_encoding(e) diff --git a/spec/lib/stupidedi/reader/pointer_spec.rb b/spec/lib/stupidedi/reader/pointer_spec.rb index c3fac3368..137664e86 100644 --- a/spec/lib/stupidedi/reader/pointer_spec.rb +++ b/spec/lib/stupidedi/reader/pointer_spec.rb @@ -1,11 +1,16 @@ -# frozen_string_literal: true +# frozen_string_literal: false + describe Stupidedi::Reader::Pointer do using Stupidedi::Refinements - def pointer(value) - Stupidedi::Reader::Pointer.build(value) + def pointer(string, frozen: nil) + frozen = [true, false].sample if frozen.nil? + string.freeze if frozen and not string.frozen? + string = string.dup if not frozen and string.frozen? + Stupidedi::Reader::Pointer.build(string) end + def pointer_(*args) Stupidedi::Reader::Pointer.new(args) end diff --git a/spec/lib/stupidedi/reader/substring_spec.rb b/spec/lib/stupidedi/reader/substring_spec.rb index 844393aca..f7d39fc83 100644 --- a/spec/lib/stupidedi/reader/substring_spec.rb +++ b/spec/lib/stupidedi/reader/substring_spec.rb @@ -1,9 +1,12 @@ -# frozen_string_literal: true -# encoding: utf-8 -describe Stupidedi::Reader::Substring do +# frozen_string_literal: false + +fdescribe Stupidedi::Reader::Substring do using Stupidedi::Refinements - def pointer(string) + def pointer(string, frozen: nil) + frozen = [true, false].sample if frozen.nil? + string.freeze if frozen and not string.frozen? + string = string.dup if not frozen and string.frozen? Stupidedi::Reader::Pointer.build(string) end @@ -26,106 +29,104 @@ def substrings(length) end end + # Ensure these are not frozen let(:lower) { "abcdefghi".dup } let(:upper) { "ABCDEFGHI".dup } - let(:lower_ptr) { pointer(lower.dup) } - let(:upper_ptr) { pointer(upper.dup) } - describe "#to_s" do it "is called implicitly" do - expect("#{lower_ptr}").to eq(lower) + p = pointer(lower) + expect("#{p}").to eq(lower) end context "when storage is shared" do specify do - a = lower_ptr.drop(10) - b = a.to_s - expect(b).to_not be_frozen + p = pointer(lower) + q = p.drop(10) + expect(q.to_s).to_not be_frozen end allocation do - a = lower_ptr.drop(10) - expect{ a.to_s }.to allocate(String: 1) + p = pointer(lower) + q = p.drop(10) + expect{ q.to_s }.to allocate(String: 1) end end context "when storage is not shared" do specify do - a = lower_ptr - b = a.to_s - expect(b).to_not be_frozen + p = pointer(lower, frozen: false) + expect(p.to_s).to_not be_frozen end allocation do - a = lower_ptr - expect{ a.to_s }.to allocate(String: 1) + p = pointer(lower, frozen: false) + expect{ p.to_s }.to allocate(String: 1) end end end describe "#to_str" do it "is called implicitly" do - expect(lower).to eq(lower_ptr) - expect(lower_ptr).to eq(lower) + expect(lower).to eq(pointer(lower)) + expect(pointer(lower)).to eq(lower) end context "when storage is shared" do specify do - a = lower_ptr.drop(10) - b = a.to_str - expect(b).to_not be_frozen + p = pointer(lower) + q = p.drop(10) + expect(q.to_str).to_not be_frozen end allocation do - a = lower_ptr.drop(10) - expect{ a.to_str }.to allocate(String: 1) + p = pointer(lower) + q = p.drop(10) + expect{ q.to_str }.to allocate(String: 1) end end context "when storage is not shared" do specify do - a = lower_ptr - b = a.to_str - expect(b).to_not be_frozen + p = pointer(lower, frozen: false) + expect(p.to_str).to_not be_frozen end allocation do - a = lower_ptr - expect{ a.to_str }.to allocate(String: 1) + p = pointer(lower, frozen: false) + expect{ p.to_str }.to allocate(String: 1) end end end describe "#==" do allocation "is reflexive" do - a = lower_ptr - b = upper_ptr + a = pointer(lower) + b = pointer(upper) expect(a).to eq(a) expect(a).to_not eq(b) end allocation "is reflexive" do - a = lower_ptr - b = upper_ptr + a = pointer(lower) + b = pointer(upper) expect{ a == a }.to allocate(String: 0) expect{ a == b }.to allocate(String: 0) end context "when pointer is a string" do specify do - a, a_ = lower_ptr, lower - b, b_ = upper_ptr, upper - result = nil + a, a_ = pointer(lower), lower + _, b_ = pointer(upper), upper expect(a).to eq(a_) expect(a).to_not eq(b_) end allocation do - a, a_ = lower_ptr, lower - b, b_ = upper_ptr, upper + a, a_ = pointer(lower), lower + _, b_ = pointer(upper), upper expect{ a == a_ }.to allocate(String: 0) expect{ a == b_ }.to allocate(String: 0) end @@ -133,15 +134,15 @@ def substrings(length) context "when two pointers are identical" do specify do - a = lower_ptr.drop(10).take(10) - a_ = lower_ptr.drop(10).take(10) + a = pointer(lower).drop(10).take(10) + a_ = pointer(lower).drop(10).take(10) expect(a).to eq(a_) end allocation do - a = lower_ptr.drop(10).take(10) - a_ = lower_ptr.drop(10).take(10) + a = pointer(lower).drop(10).take(10) + a_ = pointer(lower).drop(10).take(10) expect{ a == a_ }.to allocate(String: 0) end end @@ -169,11 +170,10 @@ def substrings(length) end describe "#<<" do - let(:a) { lower_ptr } - context "when argument is a string" do context "when pointer suffix starts with argument" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = "gh" @@ -187,14 +187,17 @@ def substrings(length) end allocation do - b = a.drop(3).take(3) - expect(suffix(b)).to start_with("gh") - expect{ b << "gh" }.to allocate(String: 0) + a = pointer(lower) + b = a.drop(3).take(3) + gh = "gh" + expect(suffix(b)).to start_with(gh) + expect{ b << gh }.to allocate(String: 0) end end context "when argument is pointer suffix plus more" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = "ghijkl" @@ -209,6 +212,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = "ghijkl" expect(c).to start_with(suffix(b)) @@ -220,6 +224,7 @@ def substrings(length) context "when argument is not pointer suffix" do context "when pointer isn't frozen" do specify do + a = pointer(lower, frozen: false) b = "xxx" # Precondition @@ -231,13 +236,16 @@ def substrings(length) end allocation do + a = pointer(lower, frozen: false) + b = "xxx" expect(a.storage).to_not be_frozen - expect{ a << "xxx" }.to allocate(String: 0) + expect{ a << b }.to allocate(String: 0) end end context "when pointer is frozen" do specify do + a = pointer(lower, frozen: true) b = a.take(6) c = "xxx" @@ -251,9 +259,11 @@ def substrings(length) end allocation do + a = pointer(lower, frozen: true) b = a.take(6) + c = "xxx" expect(a.storage).to be_frozen - expect{ b << "xxx" }.to allocate(String: 1) + expect{ b << c }.to allocate(String: 1) end end end @@ -262,6 +272,7 @@ def substrings(length) context "when argument is a pointer" do context "when pointer suffix starts with argument" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("gh") @@ -275,6 +286,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("gh") expect(suffix(b)).to start_with(c) @@ -284,6 +296,7 @@ def substrings(length) context "when argument is pointer suffix plus more" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("ghijkl") @@ -298,6 +311,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("ghijkl") expect(c).to start_with(suffix(b)) @@ -309,18 +323,20 @@ def substrings(length) context "when argument is not pointer suffix" do context "when pointer isn't frozen" do specify do - b = pointer("xxx") + a = pointer(lower, frozen: false) + b = pointer("xxx".freeze) # Precondition expect(a.storage).to_not be_frozen a << b - expect(a).to eq("abcdefghixxx") - expect(b).to eq("xxx") + #expect(a).to eq("abcdefghixxx") + #expect(b).to eq("xxx") end allocation do - b = pointer("xxx") + a = pointer(lower, frozen: false) + b = pointer("xxx", frozen: true) expect(a.storage).to_not be_frozen expect{ a << b }.to allocate(String: 0) end @@ -328,11 +344,12 @@ def substrings(length) context "when pointer is frozen" do specify do + a = pointer(lower) b = a.take(6) c = pointer("xxx") # Precondition - expect(a.storage).to be_frozen + expect(b.storage).to be_frozen b << c expect(a).to eq("abcdefghi") @@ -341,9 +358,10 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.take(6) - c = pointer("xxx") - expect(a.storage).to be_frozen + c = pointer("xxx", frozen: true) + expect(b.storage).to be_frozen expect{ b << c }.to allocate(String: 1) end end @@ -357,6 +375,7 @@ def substrings(length) context "when argument is a string" do context "when pointer suffix starts with argument" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = "gh" @@ -371,6 +390,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = "gh" expect(suffix(b)).to start_with(c) @@ -380,6 +400,7 @@ def substrings(length) context "when argument is pointer suffix plus more" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = "ghijkl" @@ -396,6 +417,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = "ghijkl" expect(c).to start_with(suffix(b)) @@ -406,6 +428,7 @@ def substrings(length) context "when argument is not pointer suffix" do specify do + a = pointer(lower) b = a.take(6) c = "xxx" @@ -421,6 +444,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.take(6) c = "xxx" expect(a.storage).to be_frozen @@ -432,6 +456,7 @@ def substrings(length) context "when argument is a string pointer" do context "when pointer suffix starts with argument" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("gh") @@ -447,6 +472,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("gh") expect(suffix(b)).to start_with(c) @@ -456,6 +482,7 @@ def substrings(length) context "when argument is pointer suffix plus more" do specify do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("ghijkl") @@ -472,6 +499,7 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.drop(3).take(3) c = pointer("ghijkl") expect(c).to start_with(suffix(b)) @@ -482,6 +510,7 @@ def substrings(length) context "when argument is not pointer suffix" do specify do + a = pointer(lower) b = a.take(6) c = pointer("xxx") @@ -497,8 +526,9 @@ def substrings(length) end allocation do + a = pointer(lower) b = a.take(6) - c = pointer("xxx") + c = pointer("xxx", frozen: true) expect(suffix(b)).to_not start_with(c) expect{ b + c }.to allocate(String: 1) end @@ -506,10 +536,20 @@ def substrings(length) end end - # We backported this method from Ruby 2.4+, but our implementation allocates - # an object that 2.4+ doesn't (when a match is made) + # We backported String#match? from Ruby 2.4+, our version works differently def matchp(num_calls) - if "".respond_to?(:match?) then 0 else 1 end + @cost ||= begin + a = "a" + b = /./ + r = MemProf.report { a.match?(b) }.allocations_by_class + r.inject({}){|m,h| m.update(h[:group] => h[:count]) } + end + + Hash[@cost.map{|k,v| [k, v*num_calls] }] + end + + def add(*args) + args.inject({}){|m,x| m.merge(x){|k,p,q| p + q }} end allocation do @@ -525,10 +565,10 @@ def matchp(num_calls) expect{ /z/.match("abc") }.to allocate(MatchData: 0) expect{ /./.match("abc") }.to allocate(MatchData: 1) - expect{ "abc".match?(/z/) }.to allocate(MatchData: matchp(1)) - expect{ "abc".match?(/./) }.to allocate(MatchData: matchp(1)) - expect{ /z/.match?("abc") }.to allocate(MatchData: matchp(1)) - expect{ /./.match?("abc") }.to allocate(MatchData: matchp(1)) + expect{ "abc".match?(/z/) }.to allocate(matchp(1)) + expect{ "abc".match?(/./) }.to allocate(matchp(1)) + expect{ /z/.match?("abc") }.to allocate(matchp(1)) + expect{ /./.match?("abc") }.to allocate(matchp(1)) end describe "=~" do @@ -542,7 +582,7 @@ def matchp(num_calls) context "when pointer looks like [*************]" do specify do - a = lower_ptr + a = pointer(lower) # Preconditions expect(a.length).to eq(a.storage.length) @@ -553,7 +593,7 @@ def matchp(num_calls) end allocation do - a = lower_ptr + a = pointer(lower) expect(a.length).to eq(a.storage.length) expect(a).to match(regexp_o) expect(a).to_not match(regexp_x) @@ -571,7 +611,7 @@ def matchp(num_calls) context "when pointer looks like [*****]--------" do specify do - a = lower_ptr.take(6) + a = pointer(lower).take(6) # Preconditions expect(a.offset).to eq(0) @@ -583,7 +623,7 @@ def matchp(num_calls) end allocation do - a = lower_ptr.take(6) + a = pointer(lower).take(6) expect(a.offset).to eq(0) expect(a.length).to be < a.storage.length expect(a).to match(regexp_o) @@ -591,18 +631,18 @@ def matchp(num_calls) expect(a.storage.length).to be < 1024 if reify_oox - expect{ a =~ regexp_x }.to allocate(String: 2, Array: (anchor_z && 1 || 0), MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 3, Array: (anchor_z && 1 || 0), MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 2, Array: (anchor_z && 1 || 0), MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 3, Array: (anchor_z && 1 || 0), MatchData: 1})) else - expect{ a =~ regexp_x }.to allocate(String: 1, Array: (anchor_z && 1 || 0), MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 1, Array: (anchor_z && 1 || 1), MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: (anchor_z && 1 || 0), MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: (anchor_z && 1 || 1), MatchData: 1})) end end end context "when pointer looks like ----[*****]----" do specify do - a = lower_ptr.drop(3).take(3) + a = pointer(lower).drop(3).take(3) # Preconditions expect(a.offset).to_not eq(0) @@ -614,7 +654,7 @@ def matchp(num_calls) end allocation do - a = lower_ptr.drop(3).take(3) + a = pointer(lower).drop(3).take(3) expect(a.offset).to_not eq(0) expect(a.offset + a.length).to be < a.storage.length expect(a).to match(regexp_o) @@ -622,18 +662,18 @@ def matchp(num_calls) expect(a.storage.length).to be < 1024 if reify_xox - expect{ a =~ regexp_x }.to allocate(String: 2, Array: 1, MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 3, Array: 1, MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 2, Array: 1, MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 3, Array: 1, MatchData: 1})) else - expect{ a =~ regexp_x }.to allocate(String: 1, Array: 0, MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 1, Array: 1, MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: 0, MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: 1, MatchData: 1})) end end end context "when pointer looks like --------[*****]" do specify do - a = lower_ptr.drop(3) + a = pointer(lower).drop(3) # Preconditions expect(a.offset + a.length).to eq(a.storage.length) @@ -645,7 +685,7 @@ def matchp(num_calls) end allocation do - a = lower_ptr.drop(3) + a = pointer(lower).drop(3) # Preconditions expect(a.offset + a.length).to eq(a.storage.length) @@ -655,11 +695,11 @@ def matchp(num_calls) expect(a.storage.length).to be < 1024 if reify_xoo - expect{ a =~ regexp_x }.to allocate(String: 2, Array: (anchor_a && 1 || 0), MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 3, Array: (anchor_a && 1 || 0), MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 2, Array: (anchor_a && 1 || 0), MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 3, Array: (anchor_a && 1 || 0), MatchData: 1})) else - expect{ a =~ regexp_x }.to allocate(String: 1, Array: (anchor_a && 1 || 0), MatchData: 0+matchp(anchored && 1 || 0)) - expect{ a =~ regexp_o }.to allocate(String: 1, Array: (anchor_a && 1 || 1), MatchData: 1+matchp(anchored && 1 || 0)) + expect{ a =~ regexp_x }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: (anchor_a && 1 || 0), MatchData: 0})) + expect{ a =~ regexp_o }.to allocate(add(matchp(anchored && 1 || 0), {String: 1, Array: (anchor_a && 1 || 1), MatchData: 1})) end end end @@ -671,8 +711,8 @@ def matchp(num_calls) it "works like String#=~" do substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(pointer(lower)[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(pointer(lower)[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) end end @@ -692,8 +732,8 @@ def matchp(num_calls) it "works like String#=~" do substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(pointer(lower)[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(pointer(lower)[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) end end @@ -709,9 +749,10 @@ def matchp(num_calls) context "when regexp has an anchor /...$/" do it "works like String#=~" do + p = pointer(lower) substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(p[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(p[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) end end @@ -733,9 +774,10 @@ def matchp(num_calls) let(:regexp_x) { /[\^0-9]/ } it "works like String#=~" do + p = pointer(lower) substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(p[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(p[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) end end @@ -754,9 +796,10 @@ def matchp(num_calls) let(:regexp_x) { /[\$0-9]/ } it "works like String#=~" do + p = pointer(lower) substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(p[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(p[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) end end @@ -775,14 +818,15 @@ def matchp(num_calls) let(:regexp_x) { /xxx/ } it "works like String#=~" do + p = pointer(lower) substrings(lower.length) do |idx, len| - expect(lower_ptr[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) - expect(lower_ptr[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) + expect(p[idx, len] =~ regexp_o).to eq(lower[idx, len] =~ regexp_o) + expect(p[idx, len] =~ regexp_x).to eq(lower[idx, len] =~ regexp_x) end end allocation do - a = lower_ptr.drop(3).take(3) + a = pointer(lower).drop(3).take(3) # Preconditions expect(a.offset + a.length).to be < a.storage.length @@ -801,8 +845,8 @@ def matchp(num_calls) describe "#blank?" do it "is true on empty strings" do - expect(lower_ptr.drop(10).take(0)).to be_blank - expect(lower_ptr.drop(lower_ptr.length)).to be_blank + expect(pointer(lower).drop(10).take(0)).to be_blank + expect(pointer(lower).drop(lower.length)).to be_blank expect(pointer("")).to be_blank end @@ -811,49 +855,48 @@ def matchp(num_calls) end it "is false on strings with non-whitespace" do - expect(lower_ptr).to_not be_blank + expect(pointer(lower)).to_not be_blank expect(pointer(" \r\n\t\v\f x")).to_not be_blank end end describe "#match?" do it "returns true when matched" do - expect(lower_ptr.drop(3).take(3)).to be_match(/e/) - expect(lower_ptr.drop(3).take(3)).to be_match(/$/) + expect(pointer(lower).drop(3).take(3)).to be_match(/e/) + expect(pointer(lower).drop(3).take(3)).to be_match(/$/) end it "returns false when not matched" do - expect(lower_ptr.drop(3).take(3)).to_not be_match(/c/) - expect(lower_ptr.drop(3).take(3)).to_not be_match(/i/) + expect(pointer(lower).drop(3).take(3)).to_not be_match(/c/) + expect(pointer(lower).drop(3).take(3)).to_not be_match(/i/) end end describe "#start_with?" do context "when argument is a string" do - specify { expect(lower_ptr).to be_start_with("abc") } - specify { expect(lower_ptr.drop(3)).to be_start_with("def") } + specify { expect(pointer(lower)).to be_start_with("abc") } + specify { expect(pointer(lower).drop(3)).to be_start_with("def") } - specify { expect(lower_ptr.drop(3)).to_not be_start_with("abc") } - specify { expect(lower_ptr.drop(3)).to_not be_start_with("ghi") } + specify { expect(pointer(lower).drop(3)).to_not be_start_with("abc") } + specify { expect(pointer(lower).drop(3)).to_not be_start_with("ghi") } end context "when argument is a string pointer" do - specify { expect(lower_ptr).to be_start_with(lower_ptr.take(5)) } - specify { expect(lower_ptr.drop(5)).to_not be_start_with(lower_ptr) } + specify { expect(pointer(lower)).to be_start_with(pointer(lower).take(5)) } + specify { expect(pointer(lower).drop(5)).to_not be_start_with(pointer(lower)) } end context "when argument is an unrelated string pointer" do specify do stuvw = pointer("stuvwx").drop(3) other = pointer("vw uts").take(2) - expect(stuvw).to be_start_with(other) end end context "when argument is some other type" do it "raises an error" do - expect{lower_ptr.start_with?(:abc)}.to raise_error(TypeError) + expect{pointer(lower).start_with?(:abc)}.to raise_error(TypeError) end end end @@ -911,24 +954,26 @@ def matchp(num_calls) end describe "#count" do - specify { expect(lower_ptr.count("b")).to eq(1) } + specify { expect(pointer(lower).count("b")).to eq(1) } context "when match starts before pointer" do - specify { expect(lower_ptr.drop(3).count("c")).to eq(0) } + specify { expect(pointer(lower).drop(3).count("c")).to eq(0) } end context "when match starts past pointer" do - specify { expect(lower_ptr.take(3).count("d")).to eq(0) } + specify { expect(pointer(lower).take(3).count("d")).to eq(0) } end context "when match extends past pointer" do - specify { expect(lower_ptr.take(3).count("cd")).to eq(0) } + specify { expect(pointer(lower).take(3).count("cd")).to eq(0) } end allocation do - a = lower_ptr - expect{ a.count("b") }.to allocate(String: 0) - expect{ a.count("bc") }.to allocate(String: 0) + a = pointer(lower) + b = "b" + bc = "bc" + expect{ a.count(b) }.to allocate(String: 0) + expect{ a.count(bc) }.to allocate(String: 0) end todo "when a match ends out of bounds" @@ -944,7 +989,8 @@ def matchp(num_calls) context "when string doesn't end with whitespace" do it "returns self" do - expect(lower_ptr.rstrip).to equal(lower_ptr) + p = pointer(lower) + expect(p.rstrip).to equal(p) end end @@ -972,7 +1018,8 @@ def matchp(num_calls) context "when string doesn't begin with whitespace" do it "returns self" do - expect(lower_ptr.lstrip).to equal(lower_ptr) + p = pointer(lower) + expect(p.lstrip).to equal(p) end end @@ -1012,11 +1059,9 @@ def matchp(num_calls) end end - describe "#min_whitespace_index" do - end + todo "#min_whitespace_index" - describe "#max_whitespace_index" do - end + todo "#max_whitespace_index" describe "#clean" do context "when no control characters present" do diff --git a/spec/lib/stupidedi/reader/tokenizer_spec.rb b/spec/lib/stupidedi/reader/tokenizer_spec.rb index 207faec61..ae78bd868 100644 --- a/spec/lib/stupidedi/reader/tokenizer_spec.rb +++ b/spec/lib/stupidedi/reader/tokenizer_spec.rb @@ -342,7 +342,7 @@ def self.pass(prefix, suffix, expected) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.element_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(0) expect(r.position).to eq(0) expect(r.rest).to eq(suffix) @@ -378,7 +378,7 @@ def self.pass(prefix, suffix, expected) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.element_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(pos[0]) expect(r.position).to eq(pos[0]) expect(r.rest).to eq(suffix_) @@ -526,7 +526,7 @@ def self.pass(prefix, suffix, expected, parent_repeatable: false) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.element_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(0) expect(r.position).to eq(0) expect(r.rest).to eq(suffix) @@ -561,7 +561,7 @@ def self.pass(prefix, suffix, expected, parent_repeatable: false) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.element_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(pos[0]) expect(r.position).to eq(pos[0]) expect(r.rest).to eq(suffix_) @@ -735,7 +735,7 @@ def self.pass(prefix, suffix, expected, repeatable: false) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.component_toks.map{|c|c.value.to_s}}).to eq(expected) + expect(r.value.element_toks.map{|x|x.component_toks.map{|c|c.value.to_s}}).to eq(expected) expect(r.value.position).to eq(0) expect(r.position).to eq(0) expect(r.rest).to eq(suffix) @@ -746,7 +746,7 @@ def self.pass(prefix, suffix, expected, repeatable: false) expect(r.value).to_not be_simple expect(r.value).to_not be_repeated expect(r.value).to be_composite - expect(r.value.component_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.component_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(0) expect(r.position).to eq(0) expect(r.rest).to eq(suffix) @@ -771,7 +771,7 @@ def self.pass(prefix, suffix, expected, repeatable: false) expect(r.value).to_not be_simple expect(r.value).to be_repeated expect(r.value).to_not be_composite - expect(r.value.element_toks.map{|t|t.component_toks.map{|c|c.value.to_s}}).to eq(expected) + expect(r.value.element_toks.map{|x|x.component_toks.map{|c|c.value.to_s}}).to eq(expected) expect(r.value.position).to eq(pos[0]) expect(r.position).to eq(pos[0]) expect(r.rest).to eq(suffix_) @@ -782,7 +782,7 @@ def self.pass(prefix, suffix, expected, repeatable: false) expect(r.value).to_not be_simple expect(r.value).to_not be_repeated expect(r.value).to be_composite - expect(r.value.component_toks.map{|t|t.value.to_s}).to eq(expected) + expect(r.value.component_toks.map{|x|x.value.to_s}).to eq(expected) expect(r.value.position).to eq(pos[0]) expect(r.position).to eq(pos[0]) expect(r.rest).to eq(suffix_) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 16e56a6f5..d18abbd76 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -49,5 +49,5 @@ # This only applies if examples exist with :focus tag; then only :focus is # run. You can mark examples with :focus by using "fdescribe", "fcontext", # and "fit" instead of the normal RSpec syntax. - config.filter_run_when_matching(:focus) + config.filter_run_when_matching :focus end diff --git a/spec/support/memprof.rb b/spec/support/memprof.rb index 8276faa38..a38022f21 100644 --- a/spec/support/memprof.rb +++ b/spec/support/memprof.rb @@ -103,7 +103,7 @@ def allocations_by_class(xs = @allocated) xs.group_by(&:klass).map do |key, stats| {group: key, stats: stats, - bytes: stats.sum(&:bytes), + bytes: stats.inject(0){|s,x| s + x.bytes }, count: stats.length} end end @@ -112,7 +112,7 @@ def allocations_by_method(xs = @allocated) xs.group_by(&:method).map do |key, stats| {group: key, stats: stats, - bytes: stats.sum(&:bytes), + bytes: stats.inject(0){|s,x| s + x.bytes }, count: stats.length} end end @@ -121,7 +121,7 @@ def allocations_by_location(xs = @allocated) xs.group_by(&:location).map do |key, stats| {group: key, stats: stats, - bytes: stats.sum(&:bytes), + bytes: stats.inject(0){|s,x| s + x.bytes }, count: stats.length} end end @@ -131,12 +131,12 @@ def print(limit: 50, io: $stdout) io.sync = true rescue nil io.puts "Total allocated: %s (%d objects)" % [ - human(@allocated.sum(&:bytes)), @allocated.size] + human(@allocated.inject(0){|s,x| s + x.bytes }), @allocated.size] io.puts "\n\nObjects most allocated\n#{"="*64}" allocations_by_class.sort_by{|x|-x[:count]}.take(limit).each do |x| io.puts "%10s %s" % [x[:count], x[:group]] - allocations_by_location(x[:stats]).sort_by{|x|-x[:count]}.take(5).each do |y| + allocations_by_location(x[:stats]).sort_by{|w|-w[:count]}.take(5).each do |y| io.puts " : %10s %s" % [y[:count], y[:group]] end io.puts