PureXML/Sources/Parsing
Mihaela Mihaljevic fe0400c3df perf(parsing): byte-path quote handling, lazy expanded-name check, byte-scan entity guard
Third profile-guided pass (#139, docs/benchmarks.md pass 27), targeting
scanContentMarkup(), which inlines the start-tag/attribute/namespace scanners
and carries ~46% of parse time.

scanAttributeValue's opening and closing quote checks ran on the Character
path (peek + advance, buffering the quote as a Character only to compare and
discard it) on every attribute value in the document; both now check the raw
byte first, reaching the byte fast path with no Character buffering, with the
Character path kept as the off-fast-path fallback for streaming sources. The
quote bytes are ASCII and non-CR/LF, so the raw byte and the normalized
stream agree, the same reasoning peekByte's other callers already rely on.

NamespaceContext.checkExpandedNames allocated a Set's native storage and
built a concatenated URI+local key string per element even when at most one
attribute carries a namespace URI, where no duplicate is possible (the
default namespace never applies to attributes, and xmlns declarations carry
no URI). Counting URI-bearing attributes first, with no allocation, and
returning early below two skips all of it on the overwhelming majority of
elements; for xml:* attributes specifically the key exceeded the small-string
limit, so this also removes a real per-element heap allocation.

EntityDecoder.decode/decodeLenient guarded with raw.contains("&"), a
grapheme-by-grapheme walk to find one ASCII byte, once per ampersand-bearing
text node or attribute value; raw.utf8.contains(0x26) finds the same byte
without decoding graphemes, the same shape as checkNameShape's colon check.

The quote-handling extraction into two helpers also resolves the cyclomatic
complexity the inline version tripped. Six new regression tests pin the
quote edge cases (empty value, single-quoted, a quote kind nested inside the
other, unterminated at end of input) plus byte/Character-path agreement for
each in the parser path differential.

Verified: full local suite (1858 tests) and full W3C XSTS suite (14383
groups) pass unchanged. Parse ~6.00x -> ~4.75x versus libxml2 at the
20000-item corpus, best of 5.
2026-07-12 12:27:00 +02:00
..
Big5Decoder.swift
Big5Table1.swift
Big5Table2.swift
Big5Table3.swift
Big5Table4.swift
Big5Table5.swift
Big5Table6.swift
Big5Table.swift
ByteDecoder.swift
ByteEncoder.swift
ByteStorage.swift perf(parsing): byte-backed Reader and bulk content runs 2026-06-10 18:48:57 +02:00
CharacterClassification.swift perf(parsing): byte-level scanning fast paths halve parse time vs libxml2 (#275) 2026-06-24 18:46:58 +02:00
CJKByteEncoder.swift
Diagnostic.swift
DoctypeScanner.swift refactor: remove three dead file-scoped functions (#330) 2026-06-26 12:04:07 +02:00
DoctypeScannerConditional.swift
DoctypeScannerEntities.swift
DoctypeScannerStrict.swift
DocumentType.swift
DTDAttListGrammar.swift
DTDContentModelGrammar.swift
EntityDecoder.swift perf(parsing): byte-path quote handling, lazy expanded-name check, byte-scan entity guard 2026-07-12 12:27:00 +02:00
EntityReplacementGrammar.swift
EntityResolver.swift
EUCJPDecoder.swift
EUCKRDecoder.swift
EUCKRTable1.swift
EUCKRTable2.swift
EUCKRTable3.swift
EUCKRTable4.swift
EUCKRTable5.swift
EUCKRTable6.swift
EUCTWDecoder.swift
EUCTWPlane11.swift
EUCTWPlane12.swift
EUCTWPlane13.swift
EUCTWPlane21.swift
EUCTWPlane22.swift
EUCTWPlane23.swift
EUCTWTable.swift
Event.swift
EventReader.swift perf(parse): split the name prefix from a scanned colon offset (#292) 2026-06-25 12:23:53 +02:00
EventReaderAttributes.swift perf(parsing): byte-path quote handling, lazy expanded-name check, byte-scan entity guard 2026-07-12 12:27:00 +02:00
EventReaderContent.swift perf(parsing): dispatch element-content markup on the byte after '<' (#276) 2026-06-24 19:25:10 +02:00
EventReaderEndTag.swift feat(xpath,parsing): public streaming surface, linear document-order at scale 2026-06-11 06:06:31 +02:00
EventReaderRecovery.swift
EventReaderValidity.swift perf(parse): bulk-copy literal runs in the entity decoder (#291) 2026-06-25 11:45:02 +02:00
ExternalID.swift
GB18030Decoder.swift
GB18030Ranges.swift
GBKDecoder.swift
GBKTable1.swift
GBKTable2.swift
GBKTable3.swift
GBKTable4.swift
GBKTable5.swift
GBKTable6.swift
InputEncoding.swift docs: align stale figures with code and the enforced XSTS gate 2026-06-19 23:32:04 +02:00
ISO2022JPDecoder.swift
JIS0208Table1.swift
JIS0208Table2.swift
JIS0208Table3.swift
JIS0212Table1.swift
JIS0212Table2.swift
Limits.swift
Mark.swift
NamespaceContext.swift perf(parsing): byte-path quote handling, lazy expanded-name check, byte-scan entity guard 2026-07-12 12:27:00 +02:00
ParsedDocument.swift
ParseError.swift
Parser.swift
ParserTreeBuild.swift perf(parse): build the TreeNode tree directly from the event stream (#295) 2026-06-25 14:15:57 +02:00
PseudoAttributeScanner.swift
PushAsync.swift
PushParser.swift
PushScanner.swift
Reader.swift perf(parsing): make entity/content expansion linear, not quadratic (#338) 2026-06-26 13:55:29 +02:00
ReaderByteRuns.swift perf(parsing): skip reference decoding for ampersand-free attribute values (#278) 2026-06-25 00:17:31 +02:00
ReadResult.swift
SAXHandler.swift
ShiftJISDecoder.swift
SingleByteEncodings.swift
SingleByteTables.swift
SourceRange.swift
StreamingDecoder.swift
StreamingDecoderEUCTW.swift
StreamingDecoderISO2022JP.swift
TextReader.swift
UnparsedEntity.swift
ValidityFinding.swift
XMLCharacter.swift perf(parsing): byte-level scanning fast paths halve parse time vs libxml2 (#275) 2026-06-24 18:46:58 +02:00
XMLDeclaration.swift