Advertisement
Guest User

Untitled

a guest
Mar 19th, 2019
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.71 KB | None | 0 0
  1. // A small set of utilities for working with Unicode and ASCII scalars. Here is what it does:
  2. //
  3. // 1. Make `UnicodeScalar` strideable. This enables ranges of Unicode Scalars such as "a"..."z".
  4. // 2. Add strideable Unicode.ASCII.Scalar (type alias `ASCII`) to enable type-safe manipulation of ASCII bytes.
  5. // 3. Define limited `+`/`-` operators for stridable types to make something like `"x" + ("A"-"a")` possible.
  6.  
  7.  
  8. // 1. Make `UnicodeScalar` strideable. This enables ranges of Unicode Scalars such as "a"..."z".
  9.  
  10. // Constants used in `Strideable` conformance extension of `Unicode.Scalar`
  11. private let invalidCount = 0xE000 - 0xD7FF
  12. private let validCount = 0x10FFFF - invalidCount
  13.  
  14. extension Unicode.Scalar: Strideable {
  15.  
  16. public func advanced(by n: Int) -> Unicode.Scalar {
  17.  
  18. let intValue = Int(value)
  19.  
  20. precondition(n >= -intValue && n <= validCount-intValue, "Out of bounds")
  21.  
  22. let newValue = value.advanced(by: n)
  23.  
  24. switch (value, newValue) {
  25.  
  26. case (0...0xD7FF, 0...0xD7FF),
  27. (0xE000...0x10FFFF, 0xE000...0x10FFFF):
  28. return Unicode.Scalar(newValue)!
  29.  
  30. case (0...0xD7FF, _):
  31. return Unicode.Scalar(newValue.advanced(by: invalidCount))!
  32.  
  33. case (0xE000...0x10FFFF, _):
  34. return Unicode.Scalar(newValue.advanced(by: -invalidCount))!
  35.  
  36. default:
  37. fatalError("Unreachable! (scalar: \(value), stride: \(n))")
  38. }
  39. }
  40.  
  41. public func distance(to other: Unicode.Scalar) -> Int {
  42.  
  43. let value = UTF32.CodeUnit.init(self)
  44. let otherValue = UTF32.CodeUnit.init(other)
  45.  
  46. switch (value, otherValue) {
  47.  
  48. case (0...0xD7FF, 0...0xD7FF),
  49. (0xE000...0x10FFFF, 0xE000...0x10FFFF):
  50. return value.distance(to: otherValue)
  51.  
  52. case (0...0xD7FF, 0xE000...0x10FFFF):
  53. return value.distance(to: otherValue) - invalidCount
  54.  
  55. case (0xE000...0x10FFFF, 0...0xD7FF):
  56. return value.distance(to: otherValue) + invalidCount
  57.  
  58. default:
  59. fatalError("Unreachable")
  60. }
  61. }
  62. }
  63.  
  64. // 2. Add Unicode.ASCII.Scalar (type alias `ASCII`) to enable type-safe manipulation of ASCII bytes.
  65.  
  66. extension Unicode.ASCII {
  67.  
  68. public struct Scalar: ExpressibleByUnicodeScalarLiteral, Strideable {
  69.  
  70. public let int8: Int8
  71. public var uint8: UInt8 { return UInt8(bitPattern: int8) }
  72. public var unicode: UnicodeScalar { return UnicodeScalar(uint8) }
  73. public var character: Character { return Character(unicode) }
  74.  
  75. public init(_ value: Int8) {
  76. if value >= 0 {
  77. int8 = value
  78. } else {
  79. fatalError("Not an ASCII code")
  80. }
  81. }
  82.  
  83. public init(_ value: UInt8) { self.init(Int8(bitPattern: value)) }
  84.  
  85. public init(_ scalar: UnicodeScalar) {
  86. guard scalar.isASCII else { fatalError("Not an ASCII literal") }
  87. int8 = Int8(scalar.value)
  88. }
  89.  
  90. public init(unicodeScalarLiteral value: UnicodeScalar) { self.init(value) }
  91.  
  92. public func advanced(by n: Int8) -> Scalar { return Scalar(int8+n) }
  93.  
  94. public func distance(to other: Scalar) -> Int8 { return other.int8 - int8 }
  95. }
  96. }
  97.  
  98. public typealias ASCII = Unicode.ASCII.Scalar
  99.  
  100.  
  101.  
  102. // 3. Define limited `+`/`-` operators for stridable types to make something like `"x" + ("A"-"a")` possible.
  103.  
  104. public extension Strideable {
  105.  
  106. static func + (lhs: Self, rhs: Self.Stride) -> Self {
  107. return lhs.advanced(by: rhs)
  108. }
  109.  
  110. static func - (lhs: Self, rhs: Self) -> Self.Stride {
  111. return rhs.distance(to: lhs)
  112. }
  113. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement