Skip to content

Commit a233485

Browse files
authored
Merge pull request #82055 from vanvoorden/string-identical
[SE-0494][StdLib] Add `isTriviallyIdentical(to:)` Methods to String and Substring
2 parents d609889 + 0ab8884 commit a233485

File tree

15 files changed

+558
-4
lines changed

15 files changed

+558
-4
lines changed

benchmark/single-source/StringTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import TestsUtils
1414
@_spi(_Unicode)
1515
import Swift
1616

17-
public var benchmarks: [BenchmarkInfo] {
17+
public let benchmarks: [BenchmarkInfo] = {
1818
var result = [
1919
BenchmarkInfo(
2020
name: "StringEqualPointerComparison",
@@ -50,7 +50,7 @@ public var benchmarks: [BenchmarkInfo] {
5050
tags: [.validation, .String]))
5151
}
5252
return result
53-
}
53+
}()
5454

5555
// FIXME(string)
5656
public func run_StringHasPrefixAscii(_ n: Int) {

include/swift/AST/RuntimeVersions.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ RUNTIME_VERSION(
171171
FUTURE
172172
)
173173

174+
RUNTIME_VERSION(
175+
(6, 4),
176+
FUTURE
177+
)
178+
174179
END_MAJOR_VERSION(6)
175180

176181
// .......................................................................... //

stdlib/public/core/Availability.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,10 @@ extension _SwiftStdlibVersion {
258258
public static var v6_2_0: Self { Self(_value: 0x060200) }
259259
@_alwaysEmitIntoClient
260260
public static var v6_3_0: Self { Self(_value: 0x060300) }
261+
@_alwaysEmitIntoClient
262+
public static var v6_4_0: Self { Self(_value: 0x060400) }
261263

262-
private static var _current: Self { .v6_3_0 }
264+
private static var _current: Self { .v6_4_0 }
263265

264266
#if hasFeature(Macros)
265267
@available(SwiftStdlib 5.7, *)

stdlib/public/core/String.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,4 +1112,41 @@ extension String {
11121112
}
11131113
}
11141114

1115-
1115+
extension String {
1116+
/// Returns a boolean value indicating whether this string is identical to
1117+
/// `other`.
1118+
///
1119+
/// Two string values are identical if there is no way to distinguish between
1120+
/// them.
1121+
///
1122+
/// For any values `a`, `b`, and `c`:
1123+
///
1124+
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
1125+
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
1126+
/// (Symmetry)
1127+
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
1128+
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
1129+
/// (Transitivity)
1130+
/// - `a.isTriviallyIdentical(b)` implies `a == b`. `a == b` does not imply `a.isTriviallyIdentical(b)`
1131+
///
1132+
/// Values produced by copying the same value, with no intervening mutations,
1133+
/// will compare identical:
1134+
///
1135+
/// ```swift
1136+
/// let d = c
1137+
/// print(c.isTriviallyIdentical(to: d))
1138+
/// // Prints true
1139+
/// ```
1140+
///
1141+
/// Comparing strings this way includes comparing (normally) hidden
1142+
/// implementation details such as the memory location of any underlying
1143+
/// string storage object. Therefore, identical strings are guaranteed to
1144+
/// compare equal with `==`, but not all equal strings are considered
1145+
/// identical.
1146+
///
1147+
/// - Complexity: O(1)
1148+
@available(StdlibDeploymentTarget 6.4, *)
1149+
public func isTriviallyIdentical(to other: Self) -> Bool {
1150+
self._guts.isTriviallyIdentical(to: other._guts)
1151+
}
1152+
}

stdlib/public/core/StringGuts.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,13 @@ extension _StringGuts {
418418
}
419419
}
420420

421+
extension _StringGuts {
422+
@inline(__always) // Performance
423+
internal func isTriviallyIdentical(to other: Self) -> Bool {
424+
self.rawBits == other.rawBits
425+
}
426+
}
427+
421428
#if _runtime(_ObjC)
422429
extension _StringGuts {
423430

stdlib/public/core/StringUTF16View.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,3 +1056,14 @@ extension String.UTF16View {
10561056
}
10571057
}
10581058
}
1059+
1060+
extension String.UTF16View {
1061+
/// Returns a boolean value indicating whether this UTF16 view
1062+
/// is trivially identical to `other`.
1063+
///
1064+
/// - Complexity: O(1)
1065+
@available(StdlibDeploymentTarget 6.4, *)
1066+
public func isTriviallyIdentical(to other: Self) -> Bool {
1067+
self._guts.isTriviallyIdentical(to: other._guts)
1068+
}
1069+
}

stdlib/public/core/StringUTF8View.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,3 +684,14 @@ extension String.UTF8View {
684684
return unsafe try _guts.withFastUTF8(body)
685685
}
686686
}
687+
688+
extension String.UTF8View {
689+
/// Returns a boolean value indicating whether this UTF8 view
690+
/// is trivially identical to `other`.
691+
///
692+
/// - Complexity: O(1)
693+
@available(StdlibDeploymentTarget 6.4, *)
694+
public func isTriviallyIdentical(to other: Self) -> Bool {
695+
self._guts.isTriviallyIdentical(to: other._guts)
696+
}
697+
}

stdlib/public/core/StringUnicodeScalarView.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,14 @@ extension String.UnicodeScalarView {
527527
return r._knownUTF16
528528
}
529529
}
530+
531+
extension String.UnicodeScalarView {
532+
/// Returns a boolean value indicating whether this unicode scalar view
533+
/// is trivially identical to `other`.
534+
///
535+
/// - Complexity: O(1)
536+
@available(StdlibDeploymentTarget 6.4, *)
537+
public func isTriviallyIdentical(to other: Self) -> Bool {
538+
self._guts.isTriviallyIdentical(to: other._guts)
539+
}
540+
}

stdlib/public/core/Substring.swift

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,18 @@ extension Substring.UTF8View {
882882
#endif // !(os(watchOS) && _pointerBitWidth(_32))
883883
}
884884

885+
extension Substring.UTF8View {
886+
/// Returns a boolean value indicating whether this UTF8 view
887+
/// is trivially identical to `other`.
888+
///
889+
/// - Complexity: O(1)
890+
@available(StdlibDeploymentTarget 6.4, *)
891+
public func isTriviallyIdentical(to other: Self) -> Bool {
892+
self._base.isTriviallyIdentical(to: other._base)
893+
&& self._bounds == other._bounds
894+
}
895+
}
896+
885897
extension Substring {
886898
@inlinable
887899
public var utf8: UTF8View {
@@ -1037,6 +1049,18 @@ extension Substring.UTF16View: BidirectionalCollection {
10371049
}
10381050
}
10391051

1052+
extension Substring.UTF16View {
1053+
/// Returns a boolean value indicating whether this UTF16 view
1054+
/// is trivially identical to `other`.
1055+
///
1056+
/// - Complexity: O(1)
1057+
@available(StdlibDeploymentTarget 6.4, *)
1058+
public func isTriviallyIdentical(to other: Self) -> Bool {
1059+
self._base.isTriviallyIdentical(to: other._base)
1060+
&& self._bounds == other._bounds
1061+
}
1062+
}
1063+
10401064
extension Substring {
10411065
@inlinable
10421066
public var utf16: UTF16View {
@@ -1281,6 +1305,18 @@ extension Substring.UnicodeScalarView: RangeReplaceableCollection {
12811305
}
12821306
}
12831307

1308+
extension Substring.UnicodeScalarView {
1309+
/// Returns a boolean value indicating whether this unicode scalar view
1310+
/// is trivially identical to `other`.
1311+
///
1312+
/// - Complexity: O(1)
1313+
@available(StdlibDeploymentTarget 6.4, *)
1314+
public func isTriviallyIdentical(to other: Self) -> Bool {
1315+
self._slice._base.isTriviallyIdentical(to: other._slice._base)
1316+
&& self._bounds == other._bounds
1317+
}
1318+
}
1319+
12841320
extension Substring: RangeReplaceableCollection {
12851321
@_specialize(where S == String)
12861322
@_specialize(where S == Substring)
@@ -1385,3 +1421,43 @@ extension Substring {
13851421
return Substring(_unchecked: Slice(base: base, bounds: r))
13861422
}
13871423
}
1424+
1425+
extension Substring {
1426+
/// Returns a boolean value indicating whether this substring is identical to
1427+
/// `other`.
1428+
///
1429+
/// Two substring values are identical if there is no way to distinguish
1430+
/// between them.
1431+
///
1432+
/// For any values `a`, `b`, and `c`:
1433+
///
1434+
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
1435+
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
1436+
/// (Symmetry)
1437+
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
1438+
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
1439+
/// (Transitivity)
1440+
/// - `a.isTriviallyIdentical(b)` implies `a == b`. `a == b` does not imply `a.isTriviallyIdentical(b)`
1441+
///
1442+
/// Values produced by copying the same value, with no intervening mutations,
1443+
/// will compare identical:
1444+
///
1445+
/// ```swift
1446+
/// let d = c
1447+
/// print(c.isTriviallyIdentical(to: d))
1448+
/// // Prints true
1449+
/// ```
1450+
///
1451+
/// Comparing substrings this way includes comparing (normally) hidden
1452+
/// implementation details such as the memory location of any underlying
1453+
/// substring storage object. Therefore, identical substrings are guaranteed
1454+
/// to compare equal with `==`, but not all equal substrings are considered
1455+
/// identical.
1456+
///
1457+
/// - Complexity: O(1)
1458+
@available(StdlibDeploymentTarget 6.4, *)
1459+
public func isTriviallyIdentical(to other: Self) -> Bool {
1460+
self._wholeGuts.isTriviallyIdentical(to: other._wholeGuts) &&
1461+
self._offsetRange == other._offsetRange
1462+
}
1463+
}

test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
// CHECK: SWIFT_INLINE_THUNK uint8_t operator [](const __StringNested::Index& i) const SWIFT_SYMBOL({{.*}});
125125
// CHECK: SWIFT_INLINE_THUNK String getDescription() const SWIFT_SYMBOL({{.*}});
126126
// CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}});
127+
// CHECK: SWIFT_INLINE_THUNK bool isTriviallyIdenticalTo(const __StringNested::UTF8View& other) const SWIFT_SYMBOL({{.*}}) {{.*}};
127128
// CHECK-NEXT: private:
128129

129130
// CHECK: class AnyKeyPath { } SWIFT_UNAVAILABLE_MSG("class 'AnyKeyPath' is not yet exposed to C++");

0 commit comments

Comments
 (0)