Skip to content

Faster Span-based URL implementation#1844

Merged
jrflat merged 2 commits intoswiftlang:mainfrom
jrflat:jflat/swift-url-v2
Mar 26, 2026
Merged

Faster Span-based URL implementation#1844
jrflat merged 2 commits intoswiftlang:mainfrom
jrflat:jflat/swift-url-v2

Conversation

@jrflat
Copy link
Copy Markdown
Contributor

@jrflat jrflat commented Mar 23, 2026

Implement a new backing class for URL focused on performance and gated behind the FOUNDATION_SWIFT_URL_V2 build flag.

Motivation:

Many common URL operations such as path manipulation or resolution (currently) involve repeated string allocations, percent-decoding, and re-parsing. By working directly with Span(s) of the underlying bytes and replacing just the encoded path during path manipulation (ensuring that nearby ranges and path-related flags are updated correctly), we see 5-8x speedup in use cases like appending or deleting path components.

The new backing type also consolidates and shares code from the Swift NSURL/CFURL implementation, which improves parsing, validation, encoding, and resolution performance (2-3x speedup), and makes it easier to maintain consistent behavior across all the types.

Modifications:

  • URL (URL.swift): When FOUNDATION_SWIFT_URL_V2 is defined, struct URL uses the new _URL backing class.

  • _URL (URL_Impl.swift): New backing class for struct URL when the v2 build flag is enabled. Stores a _URLInfo and uses Span<UInt8> in its methods where applicable to avoid intermediate String allocations.

  • _URLInfo (URL_Info.swift): New storage struct holding the URL string, flags, and component ranges (of UTF8 bytes). Conforms to the existing _URLParseable and _URLHeader protocols (shared with __CFSmallURLImpl and __CFBigURLImpl), so it plugs directly into the same parsing and resolution functions that Swift CFURL uses. Provides parse(string:) and parse(filePath:) entry points, file path info construction, and a replacing(path:) method for efficient path-only mutations that update flags and shift query/fragment ranges without re-parsing.

  • Span+Path.swift: Span<UInt8> extensions for path and path component operations.

  • URL_File.swift: Extracted finalPathLength, parseFinalFileSystemRepresentation, parsePOSIXPath, and parseWindowsPath from URL_C+File.swift into URL static methods to share between implementations.

  • URL_Parsing.swift: Moved the free parsing, validation, and encoding functions into a URL extension (indentation change). Removed #if FOUNDATION_FRAMEWORK guards to use these for _URLInfo on all platforms.

  • URL_Resolution.swift: Removed #if FOUNDATION_FRAMEWORK guards.

  • URLEncoder.swift: Removed #if FOUNDATION_FRAMEWORK guards.

Result:

Ubuntu 24.04 `FOUNDATION_SWIFT_URL_V2` vs. Baseline Performance Swift URL v2 vs v1 Performance Linux

When FOUNDATION_SWIFT_URL_V2 is enabled, URL operations are significantly faster. The flag is not yet enabled, but has been tested. It can be enabled for swift-foundation in a separate PR after further cross-repo testing.

When enabled, URL, NSURL, and CFURL share the same Swift code for parsing, percent-encoding, file path initialization, and resolution.

Bug fixes/compatibility behaviors:

  • Prevents double-encoding of already-percent-encoded characters when another invalid character exists in the component (deviating from URLComponents encoding to match original CFURL byte encoding behavior and the behavior of most other RFC 3986 and WHATWG parsers). Will resolve issues like Double encoding of query component #1190 when enabled.
  • Allows [ and ] unencoded in the path, query, and fragment via Allow square brackets in Swift CFURL path, query, and fragment #1802, matching WHATWG behavior.
  • standardized now preserves leading .. segments in relative paths so they're not removed until resolution.
  • File path colon-encoding in the first relative path segment is more lenient when the character preceding the colon cannot be part of a scheme (e.g. %43: is not mistaken for a scheme).
  • appendingPathExtension rejects extensions containing invalid characters that would be problematic when decoded (e.g. spaces or Unicode directional override characters) instead of storing them percent-encoded.

Testing:

  • Added unit tests for path components, last path component, path extensions, appending/deleting path extensions, standardization edge cases, base URL query/fragment inheritance, data representation round-trips, and standardizing file URLs with symlinks.
  • Added benchmarks for file and non-file URL path manipulation.
  • Tested on Darwin, Linux, and Windows with and without FOUNDATION_SWIFT_URL_V2 build flag (e.g. swift test -Xswiftc -DFOUNDATION_SWIFT_URL_V2).

@jrflat jrflat requested a review from a team as a code owner March 23, 2026 04:15
@jrflat
Copy link
Copy Markdown
Contributor Author

jrflat commented Mar 23, 2026

@swift-ci please test

@jrflat jrflat changed the title Faster Swift URL implementation Faster Span-based URL implementation Mar 23, 2026
@jrflat
Copy link
Copy Markdown
Contributor Author

jrflat commented Mar 23, 2026

@swift-ci please test

@jrflat
Copy link
Copy Markdown
Contributor Author

jrflat commented Mar 23, 2026

I'd also like to investigate changing final class _URL to be a struct outside of FOUNDATION_FRAMEWORK and seeing if there are performance wins, but that requires some decent refactoring around _URLProtocol and its conformers to change all inits to static factory methods. Since that would touch un-guarded code and this PR is already fairly large, I'd prefer to do that in a follow-up PR.

@jrflat jrflat requested review from jmschonfeld and parkera March 26, 2026 16:35
@jrflat jrflat merged commit 1f52be2 into swiftlang:main Mar 26, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants