Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // A small set of utilities for working with Unicode and ASCII scalars. Here is what it does:
- //
- // 1. Make `UnicodeScalar` strideable. This enables ranges of Unicode Scalars such as "a"..."z".
- // 2. Add strideable Unicode.ASCII.Scalar (type alias `ASCII`) to enable type-safe manipulation of ASCII bytes.
- // 3. Define limited `+`/`-` operators for stridable types to make something like `"x" + ("A"-"a")` possible.
- // 1. Make `UnicodeScalar` strideable. This enables ranges of Unicode Scalars such as "a"..."z".
- // Constants used in `Strideable` conformance extension of `Unicode.Scalar`
- private let invalidCount = 0xE000 - 0xD7FF
- private let validCount = 0x10FFFF - invalidCount
- extension Unicode.Scalar: Strideable {
- public func advanced(by n: Int) -> Unicode.Scalar {
- let intValue = Int(value)
- precondition(n >= -intValue && n <= validCount-intValue, "Out of bounds")
- let newValue = value.advanced(by: n)
- switch (value, newValue) {
- case (0...0xD7FF, 0...0xD7FF),
- (0xE000...0x10FFFF, 0xE000...0x10FFFF):
- return Unicode.Scalar(newValue)!
- case (0...0xD7FF, _):
- return Unicode.Scalar(newValue.advanced(by: invalidCount))!
- case (0xE000...0x10FFFF, _):
- return Unicode.Scalar(newValue.advanced(by: -invalidCount))!
- default:
- fatalError("Unreachable! (scalar: \(value), stride: \(n))")
- }
- }
- public func distance(to other: Unicode.Scalar) -> Int {
- let value = UTF32.CodeUnit.init(self)
- let otherValue = UTF32.CodeUnit.init(other)
- switch (value, otherValue) {
- case (0...0xD7FF, 0...0xD7FF),
- (0xE000...0x10FFFF, 0xE000...0x10FFFF):
- return value.distance(to: otherValue)
- case (0...0xD7FF, 0xE000...0x10FFFF):
- return value.distance(to: otherValue) - invalidCount
- case (0xE000...0x10FFFF, 0...0xD7FF):
- return value.distance(to: otherValue) + invalidCount
- default:
- fatalError("Unreachable")
- }
- }
- }
- // 2. Add Unicode.ASCII.Scalar (type alias `ASCII`) to enable type-safe manipulation of ASCII bytes.
- extension Unicode.ASCII {
- public struct Scalar: ExpressibleByUnicodeScalarLiteral, Strideable {
- public let int8: Int8
- public var uint8: UInt8 { return UInt8(bitPattern: int8) }
- public var unicode: UnicodeScalar { return UnicodeScalar(uint8) }
- public var character: Character { return Character(unicode) }
- public init(_ value: Int8) {
- if value >= 0 {
- int8 = value
- } else {
- fatalError("Not an ASCII code")
- }
- }
- public init(_ value: UInt8) { self.init(Int8(bitPattern: value)) }
- public init(_ scalar: UnicodeScalar) {
- guard scalar.isASCII else { fatalError("Not an ASCII literal") }
- int8 = Int8(scalar.value)
- }
- public init(unicodeScalarLiteral value: UnicodeScalar) { self.init(value) }
- public func advanced(by n: Int8) -> Scalar { return Scalar(int8+n) }
- public func distance(to other: Scalar) -> Int8 { return other.int8 - int8 }
- }
- }
- public typealias ASCII = Unicode.ASCII.Scalar
- // 3. Define limited `+`/`-` operators for stridable types to make something like `"x" + ("A"-"a")` possible.
- public extension Strideable {
- static func + (lhs: Self, rhs: Self.Stride) -> Self {
- return lhs.advanced(by: rhs)
- }
- static func - (lhs: Self, rhs: Self) -> Self.Stride {
- return rhs.distance(to: lhs)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement