@@ -84,35 +84,36 @@ extension String {
84
84
}
85
85
}
86
86
87
- #if _runtime(_ObjC)
88
- /// Determines if `theString` starts with `prefix` comparing the strings under
89
- /// canonical equivalence.
90
- @_inlineable // FIXME(sil-serialize-all)
91
- @_versioned // FIXME(sil-serialize-all)
92
- @_silgen_name ( " swift_stdlib_NSStringHasPrefixNFD " )
93
- internal func _stdlib_NSStringHasPrefixNFD(
94
- _ theString: AnyObject , _ prefix: AnyObject ) -> Bool
95
87
96
- @_inlineable // FIXME(sil-serialize-all)
97
- @_versioned // FIXME(sil-serialize-all)
98
- @_silgen_name ( " swift_stdlib_NSStringHasPrefixNFDPointer " )
99
- internal func _stdlib_NSStringHasPrefixNFDPointer(
100
- _ theString: OpaquePointer , _ prefix: OpaquePointer ) -> Bool
88
+ // TODO: since this is generally useful, make public via evolution proposal.
89
+ extension BidirectionalCollection {
90
+ @_inlineable
91
+ @_versioned
92
+ internal func _ends< Suffix: BidirectionalCollection > (
93
+ with suffix: Suffix , by areEquivalent: ( Element , Element ) -> Bool
94
+ ) -> Bool where Suffix. Element == Element {
95
+ var ( i, j) = ( self . endIndex, suffix. endIndex)
96
+ while i != self . startIndex, j != suffix. startIndex {
97
+ self . formIndex ( before: & i)
98
+ suffix. formIndex ( before: & j)
99
+ if !areEquivalent( self [ i] , suffix [ j] ) { return false }
100
+ }
101
+ return j == suffix. startIndex
102
+ }
103
+ }
104
+
105
+ extension BidirectionalCollection where Element: Equatable {
106
+ @_inlineable
107
+ @_versioned
108
+ internal func _ends< Suffix: BidirectionalCollection > (
109
+ with suffix: Suffix
110
+ ) -> Bool where Suffix. Element == Element {
111
+ return _ends ( with: suffix, by: == )
112
+ }
113
+ }
101
114
102
- /// Determines if `theString` ends with `suffix` comparing the strings under
103
- /// canonical equivalence.
104
- @_inlineable // FIXME(sil-serialize-all)
105
- @_versioned // FIXME(sil-serialize-all)
106
- @_silgen_name ( " swift_stdlib_NSStringHasSuffixNFD " )
107
- internal func _stdlib_NSStringHasSuffixNFD(
108
- _ theString: AnyObject , _ suffix: AnyObject ) -> Bool
109
- @_inlineable // FIXME(sil-serialize-all)
110
- @_versioned // FIXME(sil-serialize-all)
111
- @_silgen_name ( " swift_stdlib_NSStringHasSuffixNFDPointer " )
112
- internal func _stdlib_NSStringHasSuffixNFDPointer(
113
- _ theString: OpaquePointer , _ suffix: OpaquePointer ) -> Bool
114
115
115
- extension String {
116
+ extension StringProtocol {
116
117
/// Returns a Boolean value indicating whether the string begins with the
117
118
/// specified prefix.
118
119
///
@@ -142,40 +143,9 @@ extension String {
142
143
///
143
144
/// - Parameter prefix: A possible prefix to test against this string.
144
145
/// - Returns: `true` if the string begins with `prefix`; otherwise, `false`.
145
- @_inlineable // FIXME(sil-serialize-all)
146
- public func hasPrefix( _ prefix: String ) -> Bool {
147
- let prefixCount = prefix. _guts. count
148
- if prefixCount == 0 {
149
- return true
150
- }
151
- if _fastPath ( !self . _guts. _isOpaque && !prefix. _guts. _isOpaque) {
152
- let result : Bool
153
- if self . _guts. isASCII && prefix. _guts. isASCII {
154
- let selfASCII = self . _guts. _unmanagedASCIIView
155
- let prefixASCII = prefix. _guts. _unmanagedASCIIView
156
- if prefixASCII. count > selfASCII. count {
157
- // Prefix is longer than self.
158
- result = false
159
- } else {
160
- result = ( 0 as CInt ) == _stdlib_memcmp (
161
- selfASCII. rawStart,
162
- prefixASCII. rawStart,
163
- prefixASCII. count)
164
- }
165
- } else {
166
- let lhsStr = _NSContiguousString ( _unmanaged: self . _guts)
167
- let rhsStr = _NSContiguousString ( _unmanaged: prefix. _guts)
168
- result = lhsStr. _unsafeWithNotEscapedSelfPointerPair ( rhsStr) {
169
- return _stdlib_NSStringHasPrefixNFDPointer ( $0, $1)
170
- }
171
- }
172
- _fixLifetime ( self )
173
- _fixLifetime ( prefix)
174
- return result
175
- }
176
- return _stdlib_NSStringHasPrefixNFD (
177
- self . _bridgeToObjectiveCImpl ( ) ,
178
- prefix. _bridgeToObjectiveCImpl ( ) )
146
+ @_inlineable
147
+ public func hasPrefix< Prefix: StringProtocol > ( _ prefix: Prefix ) -> Bool {
148
+ return self . starts ( with: prefix)
179
149
}
180
150
181
151
/// Returns a Boolean value indicating whether the string ends with the
@@ -207,15 +177,52 @@ extension String {
207
177
///
208
178
/// - Parameter suffix: A possible suffix to test against this string.
209
179
/// - Returns: `true` if the string ends with `suffix`; otherwise, `false`.
180
+ @_inlineable
181
+ public func hasSuffix< Suffix: StringProtocol > ( _ suffix: Suffix ) -> Bool {
182
+ return self . _ends ( with: suffix)
183
+ }
184
+ }
185
+
186
+ extension String {
187
+ @_inlineable // FIXME(sil-serialize-all)
188
+ public func hasPrefix( _ prefix: String ) -> Bool {
189
+ let prefixCount = prefix. _guts. count
190
+ if prefixCount == 0 { return true }
191
+
192
+ if _fastPath ( !self . _guts. _isOpaque && !prefix. _guts. _isOpaque) {
193
+ if self . _guts. isASCII && prefix. _guts. isASCII {
194
+ let result : Bool
195
+ let selfASCII = self . _guts. _unmanagedASCIIView
196
+ let prefixASCII = prefix. _guts. _unmanagedASCIIView
197
+ if prefixASCII. count > selfASCII. count {
198
+ // Prefix is longer than self.
199
+ result = false
200
+ } else {
201
+ result = ( 0 as CInt ) == _stdlib_memcmp (
202
+ selfASCII. rawStart,
203
+ prefixASCII. rawStart,
204
+ prefixASCII. count)
205
+ }
206
+ _fixLifetime ( self )
207
+ _fixLifetime ( prefix)
208
+ return result
209
+ }
210
+ else {
211
+
212
+ }
213
+ }
214
+
215
+ return self . starts ( with: prefix)
216
+ }
217
+
210
218
@_inlineable // FIXME(sil-serialize-all)
211
219
public func hasSuffix( _ suffix: String ) -> Bool {
212
220
let suffixCount = suffix. _guts. count
213
- if suffixCount == 0 {
214
- return true
215
- }
221
+ if suffixCount == 0 { return true }
222
+
216
223
if _fastPath ( !self . _guts. _isOpaque && !suffix. _guts. _isOpaque) {
217
- let result : Bool
218
224
if self . _guts. isASCII && suffix. _guts. isASCII {
225
+ let result : Bool
219
226
let selfASCII = self . _guts. _unmanagedASCIIView
220
227
let suffixASCII = suffix. _guts. _unmanagedASCIIView
221
228
if suffixASCII. count > self . _guts. count {
@@ -227,26 +234,15 @@ extension String {
227
234
suffixASCII. rawStart,
228
235
suffixASCII. count)
229
236
}
230
- } else {
231
- let lhsStr = _NSContiguousString ( _unmanaged: self . _guts)
232
- let rhsStr = _NSContiguousString ( _unmanaged: suffix. _guts)
233
- result = lhsStr. _unsafeWithNotEscapedSelfPointerPair ( rhsStr) {
234
- return _stdlib_NSStringHasSuffixNFDPointer ( $0, $1)
235
- }
237
+ _fixLifetime ( self )
238
+ _fixLifetime ( suffix)
239
+ return result
236
240
}
237
- _fixLifetime ( self )
238
- _fixLifetime ( suffix)
239
- return result
240
241
}
241
- return _stdlib_NSStringHasSuffixNFD (
242
- self . _bridgeToObjectiveCImpl ( ) ,
243
- suffix. _bridgeToObjectiveCImpl ( ) )
242
+
243
+ return self . _ends ( with: suffix)
244
244
}
245
245
}
246
- #else
247
- // FIXME: Implement hasPrefix and hasSuffix without objc
248
- // rdar://problem/18878343
249
- #endif
250
246
251
247
// Conversions to string from other types.
252
248
extension String {
0 commit comments