Skip to content

Commit 5620b39

Browse files
authored
Merge pull request apple#636 from tbkka/perf-text-bool
Perf: direct parsing of bool in text format
2 parents ea2a90e + c2dc496 commit 5620b39

File tree

3 files changed

+71
-11
lines changed

3 files changed

+71
-11
lines changed

Performance/generators/swift.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ function print_swift_set_field() {
2727
echo " }"
2828
;;
2929
repeated\ bool)
30-
echo " message.field$num = [true, false, true, false, true, false, true, false]"
30+
echo " for _ in 0..<repeatedCount {"
31+
echo " message.field$num.append(true)"
32+
echo " }"
3133
;;
3234
repeated\ string)
3335
echo " for _ in 0..<repeatedCount {"

Sources/SwiftProtobuf/TextFormatScanner.swift

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ private let asciiUpperE = UInt8(ascii: "E")
5454
private let asciiLowerF = UInt8(ascii: "f")
5555
private let asciiUpperF = UInt8(ascii: "F")
5656
private let asciiLowerI = UInt8(ascii: "i")
57+
private let asciiLowerL = UInt8(ascii: "l")
5758
private let asciiLowerN = UInt8(ascii: "n")
5859
private let asciiLowerR = UInt8(ascii: "r")
60+
private let asciiLowerS = UInt8(ascii: "s")
5961
private let asciiLowerT = UInt8(ascii: "t")
6062
private let asciiUpperT = UInt8(ascii: "T")
6163
private let asciiLowerU = UInt8(ascii: "u")
@@ -720,6 +722,20 @@ internal struct TextFormatScanner {
720722
return d
721723
}
722724

725+
// Skip specified characters if they all match
726+
private mutating func skipOptionalCharacters(bytes: [UInt8]) {
727+
let start = p
728+
for b in bytes {
729+
if p == end || p[0] != b {
730+
p = start
731+
return
732+
}
733+
p += 1
734+
}
735+
}
736+
737+
// Skip following keyword if it matches (case-insensitively)
738+
// the given keyword (specified as a series of bytes).
723739
private mutating func skipOptionalKeyword(bytes: [UInt8]) -> Bool {
724740
let start = p
725741
for b in bytes {
@@ -817,20 +833,47 @@ internal struct TextFormatScanner {
817833
throw TextFormatDecodingError.malformedText
818834
}
819835
let c = p[0]
836+
p += 1
837+
let result: Bool
820838
switch c {
821-
case asciiZero, asciiOne, asciiLowerF, asciiUpperF, asciiLowerT, asciiUpperT:
822-
switch parseIdentifier() {
823-
case "0", "f", "false", "False":
824-
return false
825-
case "1", "t", "true", "True":
826-
return true
827-
default:
828-
break
839+
case asciiZero:
840+
result = false
841+
case asciiOne:
842+
result = true
843+
case asciiLowerF, asciiUpperF:
844+
if p != end {
845+
let alse = [asciiLowerA, asciiLowerL, asciiLowerS, asciiLowerE]
846+
skipOptionalCharacters(bytes: alse)
847+
}
848+
result = false
849+
case asciiLowerT, asciiUpperT:
850+
if p != end {
851+
let rue = [asciiLowerR, asciiLowerU, asciiLowerE]
852+
skipOptionalCharacters(bytes: rue)
829853
}
854+
result = true
830855
default:
831-
break
856+
throw TextFormatDecodingError.malformedText
857+
}
858+
if p == end {
859+
return result
860+
}
861+
switch p[0] {
862+
case asciiSpace,
863+
asciiTab,
864+
asciiNewLine,
865+
asciiCarriageReturn,
866+
asciiHash,
867+
asciiComma,
868+
asciiSemicolon,
869+
asciiCloseSquareBracket,
870+
asciiCloseCurlyBracket,
871+
asciiCloseAngleBracket:
872+
skipWhitespace()
873+
return result
874+
default:
875+
throw TextFormatDecodingError.malformedText
832876
}
833-
throw TextFormatDecodingError.malformedText
834877
}
835878

836879
internal mutating func nextOptionalEnumName() throws -> UnsafeBufferPointer<UInt8>? {

Tests/SwiftProtobufTests/Test_TextFormat_proto3.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ class Test_TextFormat_proto3: XCTestCase, PBTestHelpers {
394394
let b = Proto3Unittest_TestAllTypes.with {$0.optionalDouble = Double.nan}
395395
XCTAssertEqual("optional_double: nan\n", b.textFormatString())
396396

397+
assertTextFormatDecodeSucceeds("optional_double: 1.0\n") {(o: MessageTestType) in
398+
return o.optionalDouble == 1.0
399+
}
400+
assertTextFormatDecodeSucceeds("12: 1.0\n") {(o: MessageTestType) in
401+
return o.optionalDouble == 1.0
402+
}
397403
assertTextFormatDecodeSucceeds("optional_double: INFINITY\n") {(o: MessageTestType) in
398404
return o.optionalDouble == Double.infinity
399405
}
@@ -475,8 +481,17 @@ class Test_TextFormat_proto3: XCTestCase, PBTestHelpers {
475481
assertTextFormatDecodeSucceeds("optional_bool:0\n ") {(o: MessageTestType) in
476482
return o.optionalBool == false
477483
}
484+
assertTextFormatDecodeSucceeds("13:0\n ") {(o: MessageTestType) in
485+
return o.optionalBool == false
486+
}
487+
assertTextFormatDecodeSucceeds("13:1\n ") {(o: MessageTestType) in
488+
return o.optionalBool == true
489+
}
478490

479491
assertTextFormatDecodeFails("optional_bool: 10\n")
492+
assertTextFormatDecodeFails("optional_bool: 1optional_double: 1.0\n")
493+
assertTextFormatDecodeFails("optional_bool: t12: 1.0\n")
494+
assertTextFormatDecodeFails("optional_bool: true12: 1.0\n")
480495
assertTextFormatDecodeFails("optional_bool: tRue\n")
481496
assertTextFormatDecodeFails("optional_bool: tr\n")
482497
assertTextFormatDecodeFails("optional_bool: tru\n")

0 commit comments

Comments
 (0)