SHARE
TWEET

Untitled

a guest Mar 19th, 2019 78 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top