Skip to content

Commit d3d3a91

Browse files
authored
Merge pull request #49 from liefran-sim/fix/parser-quadratic-performance
Fix O(n²) performance in ServerEventParser.parse()
2 parents 713f8c0 + 016d1d1 commit d3d3a91

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

Sources/EventSource/EventParser.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,31 @@ struct ServerEventParser: EventParser {
2626
static let colon: UInt8 = 0x3A
2727

2828
mutating func parse(_ data: Data) -> [EVEvent] {
29-
let (separatedMessages, remainingData) = splitBuffer(for: buffer + data)
29+
// Append in-place (amortized O(1) when buffer has capacity)
30+
buffer.append(data)
31+
32+
// Quick check: only scan the newly added region + small overlap for separator.
33+
// This avoids O(n) full-buffer scan on every chunk when no separator is present.
34+
let separators: [[UInt8]] = [[Self.lf, Self.lf], [Self.cr, Self.lf, Self.cr, Self.lf]]
35+
let maxSeparatorLength = 4 // \r\n\r\n is the longest
36+
let searchStart = max(buffer.startIndex, buffer.endIndex - data.count - maxSeparatorLength)
37+
let tailRegion = buffer[searchStart...]
38+
39+
var hasSeparator = false
40+
for separator in separators {
41+
if tailRegion.range(of: Data(separator)) != nil {
42+
hasSeparator = true
43+
break
44+
}
45+
}
46+
47+
guard hasSeparator else {
48+
// No separator in the new region — nothing to parse yet
49+
return []
50+
}
51+
52+
// Separator found — do the full split (only runs when we have complete messages)
53+
let (separatedMessages, remainingData) = splitBuffer(for: buffer)
3054
buffer = remainingData
3155
return parseBuffer(for: separatedMessages)
3256
}

0 commit comments

Comments
 (0)