From e694f861fd21a946a143eb9c5d4b63dcdd879ef0 Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Thu, 16 Oct 2025 14:42:38 -0700 Subject: [PATCH 1/6] [stdlib] string identical --- benchmark/single-source/StringTests.swift | 14 +++ benchmark/single-source/SubstringTest.swift | 9 ++ stdlib/public/core/String.swift | 40 +++++- stdlib/public/core/Substring.swift | 41 ++++++ test/stdlib/StringAPI.swift | 37 ++++++ test/stdlib/subString.swift | 132 ++++++++++++++++++++ 6 files changed, 272 insertions(+), 1 deletion(-) diff --git a/benchmark/single-source/StringTests.swift b/benchmark/single-source/StringTests.swift index bcc43a263377..4940e8ce3196 100644 --- a/benchmark/single-source/StringTests.swift +++ b/benchmark/single-source/StringTests.swift @@ -40,6 +40,10 @@ public var benchmarks: [BenchmarkInfo] { runFunction: run_StringHasSuffixUnicode, tags: [.validation, .api, .String], legacyFactor: 1000), + BenchmarkInfo( + name: "StringIdentical", + runFunction: run_StringIdentical, + tags: [.validation, .api, .String]), ] if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { @@ -1676,3 +1680,13 @@ public func run_iterateWords(_ n: Int) { blackHole(swiftOrgHTML._words) } } + +public func run_StringIdentical(_ n: Int) { + let str1 = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. " + let str2 = str1 + for _ in 0 ..< n { + for _ in 0 ..< 100_000 { + check(str1.isTriviallyIdentical(to: str2)) + } + } +} diff --git a/benchmark/single-source/SubstringTest.swift b/benchmark/single-source/SubstringTest.swift index 71ef0c774f26..8ccb340b3ce3 100644 --- a/benchmark/single-source/SubstringTest.swift +++ b/benchmark/single-source/SubstringTest.swift @@ -30,6 +30,7 @@ public let benchmarks = [ BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringIdentical", runFunction: run_SubstringIdentical, tags: [.validation, .String]), ] // A string that doesn't fit in small string storage and doesn't fit in Latin-1 @@ -332,3 +333,11 @@ public func run _LessSubstringSubstringGenericStringProtocol(_ n: Int) { } } */ + +@inline(never) +public func run_SubstringIdentical(_ n: Int) { + let (a, b) = (ss1, ss1) + for _ in 1...n*500 { + blackHole(a.isTriviallyIdentical(to: b)) + } +} diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index e6715e91cc6e..bab421dbacd2 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1112,4 +1112,42 @@ extension String { } } - +extension String { + /// Returns a boolean value indicating whether this string is identical to + /// `other`. + /// + /// Two string values are identical if there is no way to distinguish between + /// them. + /// + /// For any values `a`, `b`, and `c`: + /// + /// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity) + /// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`. + /// (Symmetry) + /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` + /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. + /// (Transitivity) + /// - `a.isTriviallyIdentical(b)` implies `a == b` + /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// + /// Values produced by copying the same value, with no intervening mutations, + /// will compare identical: + /// + /// ```swift + /// let d = c + /// print(c.isTriviallyIdentical(to: d)) + /// // Prints true + /// ``` + /// + /// Comparing strings this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// string storage object. Therefore, identical strings are guaranteed to + /// compare equal with `==`, but not all equal strings are considered + /// identical. + /// + /// - Performance: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._guts.rawBits == other._guts.rawBits + } +} diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index e4e91b6a02a4..a69a08b90a4b 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1385,3 +1385,44 @@ extension Substring { return Substring(_unchecked: Slice(base: base, bounds: r)) } } + +extension Substring { + /// Returns a boolean value indicating whether this substring is identical to + /// `other`. + /// + /// Two substring values are identical if there is no way to distinguish + /// between them. + /// + /// For any values `a`, `b`, and `c`: + /// + /// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity) + /// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`. + /// (Symmetry) + /// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)` + /// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`. + /// (Transitivity) + /// - `a.isTriviallyIdentical(b)` implies `a == b` + /// - `a == b` does not imply `a.isTriviallyIdentical(b)` + /// + /// Values produced by copying the same value, with no intervening mutations, + /// will compare identical: + /// + /// ```swift + /// let d = c + /// print(c.isTriviallyIdentical(to: d)) + /// // Prints true + /// ``` + /// + /// Comparing substrings this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// substring storage object. Therefore, identical substrings are guaranteed + /// to compare equal with `==`, but not all equal substrings are considered + /// identical. + /// + /// - Performance: O(1) + @_alwaysEmitIntoClient + public func isTriviallyIdentical(to other: Self) -> Bool { + self._wholeGuts.rawBits == other._wholeGuts.rawBits && + self._offsetRange == other._offsetRange + } +} diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index fb33db9b53ee..d85cfb872fb7 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -533,4 +533,41 @@ StringTests.test("hasPrefix/hasSuffix vs Character boundaries") { expectFalse(s2.hasSuffix("\n")) } +StringTests.test("isTriviallyIdentical(to:) small ascii") { + let a = "Hello" + let b = "Hello" + + precondition(a == b) + + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) + expectTrue(a.isTriviallyIdentical(to: b)) // Both small ASCII strings + expectTrue(b.isTriviallyIdentical(to: a)) +} + +StringTests.test("isTriviallyIdentical(to:) small unicode") { + let a = "Cafe\u{301}" + let b = "Cafe\u{301}" + let c = "Café" + + precondition(a == b) + precondition(b == c) + + expectTrue(a.isTriviallyIdentical(to: b)) + expectTrue(b.isTriviallyIdentical(to: a)) + expectFalse(a.isTriviallyIdentical(to: c)) + expectFalse(b.isTriviallyIdentical(to: c)) +} + +StringTests.test("isTriviallyIdentical(to:) large ascii") { + let a = String(repeating: "foo", count: 1000) + let b = String(repeating: "foo", count: 1000) + + precondition(a == b) + + expectFalse(a.isTriviallyIdentical(to: b)) // Two large, distinct native strings + expectTrue(a.isTriviallyIdentical(to: a)) + expectTrue(b.isTriviallyIdentical(to: b)) +} + runAllTests() diff --git a/test/stdlib/subString.swift b/test/stdlib/subString.swift index 2a7b9e58db2d..78c6d8cb612e 100644 --- a/test/stdlib/subString.swift +++ b/test/stdlib/subString.swift @@ -31,6 +31,41 @@ func checkHasContiguousStorageSubstring(_ x: Substring.UTF8View) { expectTrue(hasStorage) } +fileprivate func slices( + _ s: String, + from: Int, + to: Int +) -> ( + Substring, + Substring, + Substring +) { + let s1 = s[s.index(s.startIndex, offsetBy: from) ..< + s.index(s.startIndex, offsetBy: to)] + let s2 = s1[s1.startIndex.. Bool { + s.allSatisfy { $0.isEmpty == false } +} + +fileprivate func allEqual( + _ s: Substring... +) -> Bool { + for i in 0.. Date: Thu, 16 Oct 2025 15:58:33 -0700 Subject: [PATCH 2/6] [stdlib] string identical Co-authored-by: Karoy Lorentey --- stdlib/public/core/String.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index bab421dbacd2..cb2ddbfb1592 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1146,7 +1146,7 @@ extension String { /// identical. /// /// - Performance: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits } From 45c37b5df98c0715a93a721410dd809281496d09 Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Thu, 16 Oct 2025 15:58:43 -0700 Subject: [PATCH 3/6] [stdlib] string identical Co-authored-by: Karoy Lorentey --- stdlib/public/core/Substring.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index a69a08b90a4b..7b61664863f1 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1420,7 +1420,7 @@ extension Substring { /// identical. /// /// - Performance: O(1) - @_alwaysEmitIntoClient + @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._wholeGuts.rawBits == other._wholeGuts.rawBits && self._offsetRange == other._offsetRange From e2938ef744850600aa5737f6dc925ab6035bd8fd Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Mon, 20 Oct 2025 11:22:36 -0700 Subject: [PATCH 4/6] [stdlib] string identical tests --- benchmark/single-source/StringTests.swift | 13 +++-- benchmark/single-source/SubstringTest.swift | 49 ++++++++++------- test/stdlib/StringAPI.swift | 27 ++++++++-- test/stdlib/subString.swift | 58 +++++++++++++++++---- 4 files changed, 110 insertions(+), 37 deletions(-) diff --git a/benchmark/single-source/StringTests.swift b/benchmark/single-source/StringTests.swift index 4940e8ce3196..579ac6f3d3ce 100644 --- a/benchmark/single-source/StringTests.swift +++ b/benchmark/single-source/StringTests.swift @@ -40,10 +40,6 @@ public var benchmarks: [BenchmarkInfo] { runFunction: run_StringHasSuffixUnicode, tags: [.validation, .api, .String], legacyFactor: 1000), - BenchmarkInfo( - name: "StringIdentical", - runFunction: run_StringIdentical, - tags: [.validation, .api, .String]), ] if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { @@ -53,6 +49,14 @@ public var benchmarks: [BenchmarkInfo] { runFunction: run_iterateWords, tags: [.validation, .String])) } + + if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { + result.append( + BenchmarkInfo( + name: "StringIdentical", + runFunction: run_StringIdentical, + tags: [.validation, .api, .String])) + } return result } @@ -1681,6 +1685,7 @@ public func run_iterateWords(_ n: Int) { } } +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) public func run_StringIdentical(_ n: Int) { let str1 = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. " let str2 = str1 diff --git a/benchmark/single-source/SubstringTest.swift b/benchmark/single-source/SubstringTest.swift index 8ccb340b3ce3..a7652ff1064b 100644 --- a/benchmark/single-source/SubstringTest.swift +++ b/benchmark/single-source/SubstringTest.swift @@ -12,26 +12,34 @@ import TestsUtils -public let benchmarks = [ - BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], - setUpFunction: { blackHole(_comparison) }), - BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), - BenchmarkInfo(name: "SubstringIdentical", runFunction: run_SubstringIdentical, tags: [.validation, .String]), -] +public var benchmarks: [BenchmarkInfo] { + var result = [ + BenchmarkInfo(name: "EqualStringSubstring", runFunction: run_EqualStringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringString", runFunction: run_EqualSubstringString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstring", runFunction: run_EqualSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "EqualSubstringSubstringGenericEquatable", runFunction: run_EqualSubstringSubstringGenericEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveFirst1", runFunction: run_SubstringRemoveFirst1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringRemoveLast1", runFunction: run_SubstringRemoveLast1, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstring", runFunction: run_LessSubstringSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "LessSubstringSubstringGenericComparable", runFunction: run_LessSubstringSubstringGenericComparable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstring", runFunction: run_StringFromLongWholeSubstring, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "StringFromLongWholeSubstringGeneric", runFunction: run_StringFromLongWholeSubstringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringComparable", runFunction: run_SubstringComparable, tags: [.validation, .api, .String], + setUpFunction: { blackHole(_comparison) }), + BenchmarkInfo(name: "SubstringEqualString", runFunction: run_SubstringEqualString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringEquatable", runFunction: run_SubstringEquatable, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongString2", runFunction: run_SubstringFromLongString, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringFromLongStringGeneric2", runFunction: run_SubstringFromLongStringGeneric, tags: [.validation, .api, .String]), + BenchmarkInfo(name: "SubstringTrimmingASCIIWhitespace", runFunction: run_SubstringTrimmingASCIIWhitespace, tags: [.validation, .api, .String]), + ] + + if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) { + result.append( + BenchmarkInfo(name: "SubstringIdentical", runFunction: run_SubstringIdentical, tags: [.validation, .String]), + ) + } + return result +} // A string that doesn't fit in small string storage and doesn't fit in Latin-1 let longWide = "fὢasὢodὢijὢadὢolὢsjὢalὢsdὢjlὢasὢdfὢijὢliὢsdὢjøὢslὢdiὢalὢiὢ" @@ -335,6 +343,7 @@ public func run _LessSubstringSubstringGenericStringProtocol(_ n: Int) { */ @inline(never) +@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, visionOS 9999, *) public func run_SubstringIdentical(_ n: Int) { let (a, b) = (ss1, ss1) for _ in 1...n*500 { diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift index d85cfb872fb7..bb3efc429221 100644 --- a/test/stdlib/StringAPI.swift +++ b/test/stdlib/StringAPI.swift @@ -533,7 +533,14 @@ StringTests.test("hasPrefix/hasSuffix vs Character boundaries") { expectFalse(s2.hasSuffix("\n")) } -StringTests.test("isTriviallyIdentical(to:) small ascii") { +StringTests.test("isTriviallyIdentical(to:) small ascii") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + let a = "Hello" let b = "Hello" @@ -545,7 +552,14 @@ StringTests.test("isTriviallyIdentical(to:) small ascii") { expectTrue(b.isTriviallyIdentical(to: a)) } -StringTests.test("isTriviallyIdentical(to:) small unicode") { +StringTests.test("isTriviallyIdentical(to:) small unicode") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + let a = "Cafe\u{301}" let b = "Cafe\u{301}" let c = "Café" @@ -559,7 +573,14 @@ StringTests.test("isTriviallyIdentical(to:) small unicode") { expectFalse(b.isTriviallyIdentical(to: c)) } -StringTests.test("isTriviallyIdentical(to:) large ascii") { +StringTests.test("isTriviallyIdentical(to:) large ascii") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + let a = String(repeating: "foo", count: 1000) let b = String(repeating: "foo", count: 1000) diff --git a/test/stdlib/subString.swift b/test/stdlib/subString.swift index 78c6d8cb612e..cfac2ec43bb2 100644 --- a/test/stdlib/subString.swift +++ b/test/stdlib/subString.swift @@ -317,9 +317,21 @@ SubstringTests.test("Substring.base") { } } -SubstringTests.test("isTriviallyIdentical(to:) small ascii") { - let (a1, a2, a3) = slices("Hello", from: 2, to: 4) - let (b1, b2, b3) = slices("Hello", from: 2, to: 4) +SubstringTests.test("isTriviallyIdentical(to:) small ascii") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = "Hello" + let b = "Hello" + + precondition(a == b) + + let (a1, a2, a3) = slices(a, from: 2, to: 4) + let (b1, b2, b3) = slices(b, from: 2, to: 4) precondition(allNotEmpty(a1, a2, a3, b1, b2, b3)) precondition(allEqual(a1, a2, a3, b1, b2, b3)) @@ -346,10 +358,24 @@ SubstringTests.test("isTriviallyIdentical(to:) small ascii") { expectTrue(a3.isTriviallyIdentical(to: b3)) } -SubstringTests.test("isTriviallyIdentical(to:) small unicode") { - let (a1, a2, a3) = slices("Hello Cafe\u{301}", from: 2, to: 4) - let (b1, b2, b3) = slices("Hello Cafe\u{301}", from: 2, to: 4) - let (c1, c2, c3) = slices("Hello Café", from: 2, to: 4) +SubstringTests.test("isTriviallyIdentical(to:) small unicode") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = "Cafe\u{301}" + let b = "Cafe\u{301}" + let c = "Café" + + precondition(a == b) + precondition(b == c) + + let (a1, a2, a3) = slices(a, from: 2, to: 4) + let (b1, b2, b3) = slices(b, from: 2, to: 4) + let (c1, c2, c3) = slices(c, from: 2, to: 4) precondition(allNotEmpty(a1, a2, a3, b1, b2, b3, c1, c2, c3)) precondition(allEqual(a1, a2, a3, b1, b2, b3, c1, c2, c3)) @@ -385,9 +411,21 @@ SubstringTests.test("isTriviallyIdentical(to:) small unicode") { expectFalse(a3.isTriviallyIdentical(to: c3)) } -SubstringTests.test("isTriviallyIdentical(to:) large ascii") { - let (a1, a2, a3) = slices(String(repeating: "Hello", count: 1000), from: 2, to: 4) - let (b1, b2, b3) = slices(String(repeating: "Hello", count: 1000), from: 2, to: 4) +SubstringTests.test("isTriviallyIdentical(to:) large ascii") +.skip(.custom( + { if #available(SwiftStdlib 6.3, *) { false } else { true } }, + reason: "Requires Swift 6.3's standard library" +)) +.code { + guard #available(SwiftStdlib 6.3, *) else { return } + + let a = String(repeating: "foo", count: 1000) + let b = String(repeating: "foo", count: 1000) + + precondition(a == b) + + let (a1, a2, a3) = slices(a, from: 2, to: 4) + let (b1, b2, b3) = slices(b, from: 2, to: 4) precondition(allNotEmpty(a1, a2, a3, b1, b2, b3)) precondition(allEqual(a1, a2, a3, b1, b2, b3)) From 28a2bb3b9246b1bca3257fb4ef8d1ebad20a386c Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Mon, 20 Oct 2025 12:17:27 -0700 Subject: [PATCH 5/6] [stdlib] string identical tests --- test/stdlib/subString.swift | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/stdlib/subString.swift b/test/stdlib/subString.swift index cfac2ec43bb2..24cc04808e6c 100644 --- a/test/stdlib/subString.swift +++ b/test/stdlib/subString.swift @@ -356,6 +356,24 @@ SubstringTests.test("isTriviallyIdentical(to:) small ascii") expectTrue(a3.isTriviallyIdentical(to: b1)) expectTrue(a3.isTriviallyIdentical(to: b2)) expectTrue(a3.isTriviallyIdentical(to: b3)) + + let c = "Hello" + + precondition(b == c) + + let (c1, c2, c3) = slices(c, from: 1, to: 3) + + expectFalse(a1.isTriviallyIdentical(to: c1)) + expectFalse(a1.isTriviallyIdentical(to: c2)) + expectFalse(a1.isTriviallyIdentical(to: c3)) + + expectFalse(a2.isTriviallyIdentical(to: c1)) + expectFalse(a2.isTriviallyIdentical(to: c2)) + expectFalse(a2.isTriviallyIdentical(to: c3)) + + expectFalse(a3.isTriviallyIdentical(to: c1)) + expectFalse(a3.isTriviallyIdentical(to: c2)) + expectFalse(a3.isTriviallyIdentical(to: c3)) } SubstringTests.test("isTriviallyIdentical(to:) small unicode") @@ -418,7 +436,7 @@ SubstringTests.test("isTriviallyIdentical(to:) large ascii") )) .code { guard #available(SwiftStdlib 6.3, *) else { return } - + let a = String(repeating: "foo", count: 1000) let b = String(repeating: "foo", count: 1000) From 6a68b0b8c40593e9b46dbb10dd36cc94718419aa Mon Sep 17 00:00:00 2001 From: Rick van Voorden Date: Mon, 20 Oct 2025 18:32:41 -0700 Subject: [PATCH 6/6] [stdlib] string identical --- stdlib/public/core/String.swift | 2 +- stdlib/public/core/Substring.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index cb2ddbfb1592..884357639a35 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -1145,7 +1145,7 @@ extension String { /// compare equal with `==`, but not all equal strings are considered /// identical. /// - /// - Performance: O(1) + /// - Complexity: O(1) @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._guts.rawBits == other._guts.rawBits diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift index 7b61664863f1..42e020197b8b 100644 --- a/stdlib/public/core/Substring.swift +++ b/stdlib/public/core/Substring.swift @@ -1419,7 +1419,7 @@ extension Substring { /// to compare equal with `==`, but not all equal substrings are considered /// identical. /// - /// - Performance: O(1) + /// - Complexity: O(1) @available(SwiftStdlib 6.3, *) public func isTriviallyIdentical(to other: Self) -> Bool { self._wholeGuts.rawBits == other._wholeGuts.rawBits &&