Skip to content

Commit f55e4ba

Browse files
committed
Directly append to the result String instead of using an array for String#inspect
* Interpreter: ~11k => ~25k for both * JVM CE: simple: 390k => 4650k utf8: 240k => 1166k * MRI 2.7.7: 2222k for both (cherry picked from commit fc0b2b9)
1 parent bf88e96 commit f55e4ba

File tree

2 files changed

+12
-19
lines changed

2 files changed

+12
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Performance:
3939

4040
* Refactor and implement more performant `MatchData#length` (#2147, @LillianZ).
4141
* Refactor and implement more performant `Array#sample` (#2148, @LillianZ).
42+
* `String#inspect` is now more efficient.
4243

4344
Changes:
4445

src/main/ruby/truffleruby/core/string.rb

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -507,34 +507,27 @@ def inspect
507507
end
508508
end
509509

510-
array = []
510+
result = '"'.dup.force_encoding(result_encoding)
511511

512512
index = 0
513513
total = bytesize
514514
while index < total
515515
char = Primitive.string_chr_at(self, index)
516516

517517
if char
518-
index += inspect_char(enc, result_encoding, ascii, unicode, index, char, array)
518+
index += inspect_char(enc, result_encoding, ascii, unicode, index, char, result)
519519
else
520-
array << "\\x#{getbyte(index).to_s(16).upcase}"
520+
result << "\\x#{getbyte(index).to_s(16).upcase}"
521521
index += 1
522522
end
523523
end
524524

525-
size = array.inject(0) { |s, chr| s + chr.bytesize }
526-
result = String.pattern size + 2, ?".ord
527-
528-
index = 1
529-
array.each do |chr|
530-
Truffle::StringOperations.copy_from(result, chr, 0, chr.bytesize, index)
531-
index += chr.bytesize
532-
end
525+
result << '"'
533526

534527
result.force_encoding(result_encoding)
535528
end
536529

537-
def inspect_char(enc, result_encoding, ascii, unicode, index, char, array)
530+
private def inspect_char(enc, result_encoding, ascii, unicode, index, char, result)
538531
consumed = char.bytesize
539532

540533
if (ascii or unicode) and consumed == 1
@@ -578,38 +571,37 @@ def inspect_char(enc, result_encoding, ascii, unicode, index, char, array)
578571
end
579572

580573
if escaped
581-
array << escaped
574+
result << escaped
582575
return consumed
583576
end
584577
end
585578
end
586579

587580
if Primitive.character_printable_p(char) && (enc == result_encoding || (ascii && char.ascii_only?))
588-
array << char
581+
result << char
589582
else
590583
code = char.ord
591584
escaped = code.to_s(16).upcase
592585

593586
if unicode
594587
if code < 0x10000
595588
pad = '0' * (4 - escaped.bytesize)
596-
array << "\\u#{pad}#{escaped}"
589+
result << "\\u#{pad}#{escaped}"
597590
else
598-
array << "\\u{#{escaped}}"
591+
result << "\\u{#{escaped}}"
599592
end
600593
else
601594
if code < 0x100
602595
pad = '0' * (2 - escaped.bytesize)
603-
array << "\\x#{pad}#{escaped}"
596+
result << "\\x#{pad}#{escaped}"
604597
else
605-
array << "\\x{#{escaped}}"
598+
result << "\\x{#{escaped}}"
606599
end
607600
end
608601
end
609602

610603
consumed
611604
end
612-
private :inspect_char
613605

614606
def prepend(*others)
615607
if others.size == 1

0 commit comments

Comments
 (0)