Skip to content

Commit c9adf7a

Browse files
committed
[stdlib] Substring: Review view creation/conversion code
1 parent b7c54ac commit c9adf7a

File tree

1 file changed

+36
-21
lines changed

1 file changed

+36
-21
lines changed

stdlib/public/core/Substring.swift

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,19 @@ public struct Substring: Sendable {
9797
@usableFromInline
9898
internal var _slice: Slice<String>
9999

100+
@_alwaysEmitIntoClient // Swift 5.7
100101
@inline(__always)
101102
internal init(_unchecked slice: Slice<String>) {
102103
self._slice = slice
103104
_invariantCheck()
104105
}
105106

107+
@_alwaysEmitIntoClient // Swift 5.7
108+
@inline(__always)
109+
internal init(_unchecked guts: _StringGuts, bounds: Range<Index>) {
110+
self.init(_unchecked: Slice(base: String(guts), bounds: bounds))
111+
}
112+
106113
@usableFromInline // This used to be @inlinable before 5.7
107114
@available(*, deprecated) // Use `init(_unchecked:)` in new code.
108115
internal init(_ slice: Slice<String>) {
@@ -728,9 +735,7 @@ extension Substring {
728735
/// Creates an instance that slices `base` at `_bounds`.
729736
@inlinable
730737
internal init(_ base: String.UTF8View, _bounds: Range<Index>) {
731-
_slice = Slice(
732-
base: String(base._guts).utf8,
733-
bounds: _bounds)
738+
_slice = Slice(base: base, bounds: _bounds)
734739
}
735740

736741
@_alwaysEmitIntoClient @inline(__always)
@@ -848,7 +853,8 @@ extension Substring {
848853
@inlinable
849854
public var utf8: UTF8View {
850855
get {
851-
return base.utf8[startIndex..<endIndex]
856+
// No need for index validation
857+
UTF8View(base.utf8, _bounds: _bounds)
852858
}
853859
set {
854860
self = Substring(newValue)
@@ -859,9 +865,12 @@ extension Substring {
859865
///
860866
/// - Complexity: O(1)
861867
public init(_ content: UTF8View) {
862-
self = String(
863-
content._slice._base._guts
864-
)[content.startIndex..<content.endIndex]
868+
// Note: We can trust that `content`'s bounds are valid, but they may not be
869+
// scalar aligned.
870+
let lower = content._wholeGuts.scalarAlign(content.startIndex)
871+
let upper = content._wholeGuts.scalarAlign(content.endIndex)
872+
let bounds = Range(_uncheckedBounds: (lower, upper))
873+
self.init(_unchecked: content._wholeGuts, bounds: bounds)
865874
}
866875
}
867876

@@ -873,9 +882,9 @@ extension String {
873882
/// - Complexity: O(N), where N is the length of the resulting `String`'s
874883
/// UTF-16.
875884
public init?(_ codeUnits: Substring.UTF8View) {
876-
let guts = codeUnits._slice._base._guts
877-
guard guts.isOnUnicodeScalarBoundary(codeUnits._slice.startIndex),
878-
guts.isOnUnicodeScalarBoundary(codeUnits._slice.endIndex) else {
885+
let guts = codeUnits._wholeGuts
886+
guard guts.isOnUnicodeScalarBoundary(codeUnits.startIndex),
887+
guts.isOnUnicodeScalarBoundary(codeUnits.endIndex) else {
879888
return nil
880889
}
881890

@@ -1001,7 +1010,8 @@ extension Substring {
10011010
@inlinable
10021011
public var utf16: UTF16View {
10031012
get {
1004-
return base.utf16[startIndex..<endIndex]
1013+
// No need for index validation
1014+
UTF16View(base.utf16, _bounds: _bounds)
10051015
}
10061016
set {
10071017
self = Substring(newValue)
@@ -1012,9 +1022,12 @@ extension Substring {
10121022
///
10131023
/// - Complexity: O(1)
10141024
public init(_ content: UTF16View) {
1015-
self = String(
1016-
content._slice._base._guts
1017-
)[content.startIndex..<content.endIndex]
1025+
// Note: We can trust that `content`'s bounds are valid, but they may not be
1026+
// scalar aligned.
1027+
let lower = content._wholeGuts.scalarAlign(content.startIndex)
1028+
let upper = content._wholeGuts.scalarAlign(content.endIndex)
1029+
let bounds = Range(_uncheckedBounds: (lower, upper))
1030+
self.init(_unchecked: content._wholeGuts, bounds: bounds)
10181031
}
10191032
}
10201033

@@ -1026,9 +1039,9 @@ extension String {
10261039
/// - Complexity: O(N), where N is the length of the resulting `String`'s
10271040
/// UTF-16.
10281041
public init?(_ codeUnits: Substring.UTF16View) {
1029-
let guts = codeUnits._slice._base._guts
1030-
guard guts.isOnUnicodeScalarBoundary(codeUnits._slice.startIndex),
1031-
guts.isOnUnicodeScalarBoundary(codeUnits._slice.endIndex) else {
1042+
let guts = codeUnits._wholeGuts
1043+
guard guts.isOnUnicodeScalarBoundary(codeUnits.startIndex),
1044+
guts.isOnUnicodeScalarBoundary(codeUnits.endIndex) else {
10321045
return nil
10331046
}
10341047

@@ -1042,6 +1055,7 @@ extension Substring {
10421055
internal var _slice: Slice<String.UnicodeScalarView>
10431056

10441057
/// Creates an instance that slices `base` at `_bounds`.
1058+
@_alwaysEmitIntoClient
10451059
internal init(
10461060
_unchecked base: String.UnicodeScalarView, bounds: Range<Index>
10471061
) {
@@ -1164,7 +1178,8 @@ extension Substring {
11641178
@inlinable
11651179
public var unicodeScalars: UnicodeScalarView {
11661180
get {
1167-
return base.unicodeScalars[startIndex..<endIndex]
1181+
// No need to validate any indices.
1182+
UnicodeScalarView(_unchecked: base.unicodeScalars, bounds: _bounds)
11681183
}
11691184
set {
11701185
self = Substring(newValue)
@@ -1175,9 +1190,9 @@ extension Substring {
11751190
///
11761191
/// - Complexity: O(1)
11771192
public init(_ content: UnicodeScalarView) {
1178-
self = String(
1179-
content._slice._base._guts
1180-
)[content.startIndex..<content.endIndex]
1193+
// No need to validate any indices.
1194+
let slice = Slice(base: String(content._wholeGuts), bounds: content._bounds)
1195+
self.init(_unchecked: slice)
11811196
}
11821197
}
11831198

0 commit comments

Comments
 (0)