Skip to content

Commit 751cf26

Browse files
committed
[Unicode.Scalar] Add RAC UTF8View
This adds new (availability-controlled) API to Unicode.Scalar, exposing the scalar's UTF-8 code units as a random-access collection similarly to how it currently exposes UTF-16 code units. Tests added.
1 parent f720459 commit 751cf26

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

stdlib/public/core/UnicodeScalar.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,51 @@ extension Unicode.Scalar.UTF16View : RandomAccessCollection {
434434
}
435435
}
436436

437+
extension Unicode.Scalar {
438+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
439+
@_fixed_layout
440+
public struct UTF8View {
441+
@inlinable
442+
internal init(value: Unicode.Scalar) {
443+
self.value = value
444+
}
445+
@usableFromInline
446+
internal var value: Unicode.Scalar
447+
}
448+
449+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
450+
@inlinable
451+
public var utf8: UTF8View { return UTF8View(value: self) }
452+
}
453+
454+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
455+
extension Unicode.Scalar.UTF8View : RandomAccessCollection {
456+
public typealias Indices = Range<Int>
457+
458+
/// The position of the first code unit.
459+
@inlinable
460+
public var startIndex: Int { return 0 }
461+
462+
/// The "past the end" position---that is, the position one
463+
/// greater than the last valid subscript argument.
464+
///
465+
/// If the collection is empty, `endIndex` is equal to `startIndex`.
466+
@inlinable
467+
public var endIndex: Int { return 0 + UTF8.width(value) }
468+
469+
/// Accesses the code unit at the specified position.
470+
///
471+
/// - Parameter position: The position of the element to access. `position`
472+
/// must be a valid index of the collection that is not equal to the
473+
/// `endIndex` property.
474+
@inlinable
475+
public subscript(position: Int) -> UTF8.CodeUnit {
476+
_precondition(position >= startIndex && position < endIndex,
477+
"Unicode.Scalar.UTF8View index is out of bounds")
478+
return value.withUTF8CodeUnits { $0[position] }
479+
}
480+
}
481+
437482
extension Unicode.Scalar {
438483
internal static var _replacementCharacter: Unicode.Scalar {
439484
return Unicode.Scalar(_value: UTF32._replacementCodeUnit)

test/stdlib/Character.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,5 +404,20 @@ UnicodeScalarTests.test("LosslessStringConvertible") {
404404
checkLosslessStringConvertible((0...127).map { UnicodeScalar(Int($0))! })
405405
}
406406

407+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
408+
UnicodeScalarTests.test("Views") {
409+
let scalars = baseScalars + continuingScalars
410+
for scalar in scalars {
411+
expectEqual(scalar, String(scalar).unicodeScalars.first!)
412+
expectEqualSequence(String(scalar).utf8, scalar.utf8)
413+
expectEqualSequence(String(scalar).utf16, scalar.utf16)
414+
415+
expectEqualSequence(String(scalar).utf8.reversed(), scalar.utf8.reversed())
416+
expectEqualSequence(
417+
String(scalar).utf16.reversed(), scalar.utf16.reversed())
418+
}
419+
}
420+
}
421+
407422
runAllTests()
408423

0 commit comments

Comments
 (0)