Skip to content

[xcodegen] Avoid an intermediate String #78291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions utils/swift-xcodegen/Sources/Xcodeproj/PropertyList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,33 +51,12 @@ extension PropertyList {
writePlistRepresentation(to: &writer)
return Data(writer.bytes)
}

/// Escapes the string for plist.
/// Finds the instances of quote (") and backward slash (\) and prepends
/// the escape character backward slash (\).
static func escape(string: String) -> String {
func needsEscape(_ char: UInt8) -> Bool {
return char == UInt8(ascii: "\\") || char == UInt8(ascii: "\"")
}

guard let pos = string.utf8.firstIndex(where: needsEscape) else {
return string
}
var newString = String(string[..<pos])
for char in string.utf8[pos...] {
if needsEscape(char) {
newString += "\\"
}
newString += String(UnicodeScalar(char))
}
return newString
}
}

fileprivate extension PropertyList {
struct UTF8Writer {
var level: Int = 0
var bytes: [UInt8] = []
private(set) var level: Int = 0
private(set) var bytes: [UInt8] = []
init() {
self += "// !$*UTF8*$!\n"
}
Expand All @@ -88,6 +67,10 @@ fileprivate extension PropertyList {
level -= 1
}

mutating func append(_ byte: UInt8) {
bytes.append(byte)
}

static func += (writer: inout UTF8Writer, str: StaticString) {
str.withUTF8Buffer { utf8 in
writer.bytes += utf8
Expand All @@ -104,6 +87,17 @@ fileprivate extension PropertyList {
self += " "
}
}

/// Appends the given string, with instances of quote (") and backward slash
/// (\) characters escaped with a backslash.
mutating func appendEscaped(_ string: String) {
for char in string.utf8 {
if char == UInt8(ascii: "\\") || char == UInt8(ascii: "\"") {
append(UInt8(ascii: "\\"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
append(UInt8(ascii: "\\"))
append(UInt8(ascii: #"\"#))

🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there's only a single character to escape I tend to prefer just writing the backslash, especially as things like #"""# look weird. I think I'd rather keep things locally consistent here, I don't feel too strongly about it though

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I do not actually have a preference, but I was curious about yours, on the off chance that a raw string had occurred to you.

}
append(char)
}
}
}

/// Private function to generate OPENSTEP-style plist representation.
Expand All @@ -116,7 +110,7 @@ fileprivate extension PropertyList {

case .string(let string):
writer += "\""
writer += PropertyList.escape(string: string)
writer.appendEscaped(string)
writer += "\""

case .array(let array):
Expand Down