Skip to content

Commit fd3725f

Browse files
committed
Merge branch 'outputstream-write-refactor' of https://github.com/aciidb0mb3r/swift-package-manager
2 parents a54c627 + ff0f977 commit fd3725f

File tree

2 files changed

+77
-29
lines changed

2 files changed

+77
-29
lines changed

Sources/Basic/OutputByteStream.swift

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,25 @@ public class OutputByteStream: OutputStream {
7373
public func write(_ byte: UInt8) {
7474
buffer.append(byte)
7575
}
76-
77-
/// Write a sequence of bytes to the buffer.
78-
public func write(_ bytes: [UInt8]) {
79-
buffer += bytes
76+
77+
/// Write the contents of a UnsafeBufferPointer<UInt8>.
78+
func write(_ ptr: UnsafeBufferPointer<UInt8>) {
79+
buffer += ptr
8080
}
8181

8282
/// Write a sequence of bytes to the buffer.
8383
public func write(_ bytes: ArraySlice<UInt8>) {
8484
buffer += bytes
8585
}
86+
87+
/// Write a sequence of bytes to the buffer.
88+
public func write(_ bytes: [UInt8]) {
89+
write(ArraySlice(bytes))
90+
}
8691

8792
/// Write a sequence of bytes to the buffer.
8893
public func write<S: Sequence where S.Iterator.Element == UInt8>(_ sequence: S) {
89-
buffer += sequence
94+
write(ArraySlice(sequence))
9095
}
9196

9297
/// Write a string to the buffer (as UTF8).
@@ -95,15 +100,15 @@ public class OutputByteStream: OutputStream {
95100
// doesn't implement this optimization: <rdar://problem/24100375> Missing fast path for [UInt8] += String.UTF8View
96101
let stringPtrStart = string._contiguousUTF8
97102
if stringPtrStart != nil {
98-
buffer += UnsafeBufferPointer(start: stringPtrStart, count: string.utf8.count)
103+
write(UnsafeBufferPointer(start: stringPtrStart, count: string.utf8.count))
99104
} else {
100-
buffer += string.utf8
105+
write(string.utf8)
101106
}
102107
}
103108

104109
/// Write a character to the buffer (as UTF8).
105110
public func write(_ character: Character) {
106-
buffer += String(character).utf8
111+
write(String(character))
107112
}
108113

109114
/// Write an arbitrary byte streamable to the buffer.
@@ -132,39 +137,39 @@ public class OutputByteStream: OutputStream {
132137
//
133138
// FIXME: Workaround: <rdar://problem/22546289> Unexpected crash with range to max value for type
134139
case 0x20...0x21, 0x23...0x5B, 0x5D...0xFE, 0xFF:
135-
buffer.append(character)
140+
write(character)
136141

137142
// Single-character escaped characters.
138143
case 0x22: // '"'
139-
buffer.append(0x5C) // '\'
140-
buffer.append(0x22) // '"'
144+
write(0x5C) // '\'
145+
write(0x22) // '"'
141146
case 0x5C: // '\\'
142-
buffer.append(0x5C) // '\'
143-
buffer.append(0x5C) // '\'
147+
write(0x5C) // '\'
148+
write(0x5C) // '\'
144149
case 0x08: // '\b'
145-
buffer.append(0x5C) // '\'
146-
buffer.append(0x62) // 'b'
150+
write(0x5C) // '\'
151+
write(0x62) // 'b'
147152
case 0x0C: // '\f'
148-
buffer.append(0x5C) // '\'
149-
buffer.append(0x66) // 'b'
153+
write(0x5C) // '\'
154+
write(0x66) // 'b'
150155
case 0x0A: // '\n'
151-
buffer.append(0x5C) // '\'
152-
buffer.append(0x6E) // 'n'
156+
write(0x5C) // '\'
157+
write(0x6E) // 'n'
153158
case 0x0D: // '\r'
154-
buffer.append(0x5C) // '\'
155-
buffer.append(0x72) // 'r'
159+
write(0x5C) // '\'
160+
write(0x72) // 'r'
156161
case 0x09: // '\t'
157-
buffer.append(0x5C) // '\'
158-
buffer.append(0x74) // 't'
162+
write(0x5C) // '\'
163+
write(0x74) // 't'
159164

160165
// Multi-character escaped characters.
161166
default:
162-
buffer.append(0x5C) // '\'
163-
buffer.append(0x75) // 'u'
164-
buffer.append(hexdigit(0))
165-
buffer.append(hexdigit(0))
166-
buffer.append(hexdigit(character >> 4))
167-
buffer.append(hexdigit(character & 0xF))
167+
write(0x5C) // '\'
168+
write(0x75) // 'u'
169+
write(hexdigit(0))
170+
write(hexdigit(0))
171+
write(hexdigit(character >> 4))
172+
write(hexdigit(character & 0xF))
168173
}
169174
}
170175
}

Tests/Basic/OutputByteStreamPerfTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,32 @@ import Basic
1919
#if false
2020

2121
class OutputByteStreamPerfTests: XCTestCase {
22+
23+
func test1MBOfByte_X10() {
24+
let byte = UInt8(0)
25+
measure {
26+
for _ in 0..<10 {
27+
let stream = OutputByteStream()
28+
for _ in 0..<(1 << 20) {
29+
stream <<< byte
30+
}
31+
XCTAssertEqual(stream.bytes.count, 1 << 20)
32+
}
33+
}
34+
}
35+
36+
func test1MBOfCharacters_X1() {
37+
measure {
38+
for _ in 0..<1 {
39+
let stream = OutputByteStream()
40+
for _ in 0..<(1 << 20) {
41+
stream <<< Character("X")
42+
}
43+
XCTAssertEqual(stream.bytes.count, 1 << 20)
44+
}
45+
}
46+
}
47+
2248
func test1MBOf16ByteArrays_X100() {
2349
// Test writing 1MB worth of 16 byte strings.
2450
let bytes16 = [UInt8](repeating: 0, count: 1 << 4)
@@ -34,6 +60,23 @@ class OutputByteStreamPerfTests: XCTestCase {
3460
}
3561
}
3662

63+
// This should give same performance as 16ByteArrays_X100.
64+
func test1MBOf16ByteArraySlice_X100() {
65+
let bytes32 = [UInt8](repeating: 0, count: 1 << 5)
66+
// Test writing 1MB worth of 16 byte strings.
67+
let bytes16 = bytes32.suffix(from: bytes32.count/2)
68+
69+
measure {
70+
for _ in 0..<100 {
71+
let stream = OutputByteStream()
72+
for _ in 0..<(1 << 16) {
73+
stream <<< bytes16
74+
}
75+
XCTAssertEqual(stream.bytes.count, 1 << 20)
76+
}
77+
}
78+
}
79+
3780
func test1MBOf1KByteArrays_X1000() {
3881
// Test writing 1MB worth of 1K byte strings.
3982
let bytes1k = [UInt8](repeating: 0, count: 1 << 10)

0 commit comments

Comments
 (0)