1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
//===--- ValidUTF8Buffer.swift - Bounded Collection of Valid UTF-8 --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Stores valid UTF8 inside an unsigned integer.
//
// Actually this basic type could be used to store any UInt8s that cannot be
// 0xFF
//
//===----------------------------------------------------------------------===//
@frozen
public struct _ValidUTF8Buffer {
public typealias Element = Unicode.UTF8.CodeUnit
@usableFromInline
internal var _biasedBits: UInt32
@inlinable
internal init(_biasedBits: UInt32) {
self._biasedBits = _biasedBits
}
@inlinable
internal init(_containing e: Element) {
_internalInvariant(
e != 192 && e != 193 && !(245...255).contains(e), "invalid UTF8 byte")
_biasedBits = UInt32(truncatingIfNeeded: e &+ 1)
}
}
extension _ValidUTF8Buffer: Sequence {
public typealias SubSequence = Slice<_ValidUTF8Buffer>
@frozen
public struct Iterator: IteratorProtocol, Sequence {
@usableFromInline
internal var _biasedBits: UInt32
@inlinable
public init(_ x: _ValidUTF8Buffer) { _biasedBits = x._biasedBits }
@inlinable
public mutating func next() -> Element? {
if _biasedBits == 0 { return nil }
defer { _biasedBits >>= 8 }
return Element(truncatingIfNeeded: _biasedBits) &- 1
}
}
@inlinable
public func makeIterator() -> Iterator {
return Iterator(self)
}
}
extension _ValidUTF8Buffer: Collection {
@frozen
public struct Index: Comparable {
@usableFromInline
internal var _biasedBits: UInt32
@inlinable
internal init(_biasedBits: UInt32) { self._biasedBits = _biasedBits }
@inlinable
public static func == (lhs: Index, rhs: Index) -> Bool {
return lhs._biasedBits == rhs._biasedBits
}
@inlinable
public static func < (lhs: Index, rhs: Index) -> Bool {
return lhs._biasedBits > rhs._biasedBits
}
}
@inlinable
public var startIndex: Index {
return Index(_biasedBits: _biasedBits)
}
@inlinable
public var endIndex: Index {
return Index(_biasedBits: 0)
}
@inlinable
public var count: Int {
return UInt32.bitWidth &>> 3 &- _biasedBits.leadingZeroBitCount &>> 3
}
@inlinable
public var isEmpty: Bool {
return _biasedBits == 0
}
@inlinable
public func index(after i: Index) -> Index {
_debugPrecondition(i._biasedBits != 0)
return Index(_biasedBits: i._biasedBits >> 8)
}
@inlinable
public subscript(i: Index) -> Element {
return Element(truncatingIfNeeded: i._biasedBits) &- 1
}
}
extension _ValidUTF8Buffer: BidirectionalCollection {
@inlinable
public func index(before i: Index) -> Index {
let offset = _ValidUTF8Buffer(_biasedBits: i._biasedBits).count
_debugPrecondition(offset != 0)
return Index(_biasedBits: _biasedBits &>> (offset &<< 3 - 8))
}
}
extension _ValidUTF8Buffer: RandomAccessCollection {
public typealias Indices = DefaultIndices<_ValidUTF8Buffer>
@inlinable
@inline(__always)
public func distance(from i: Index, to j: Index) -> Int {
_debugPrecondition(_isValid(i))
_debugPrecondition(_isValid(j))
return (
i._biasedBits.leadingZeroBitCount - j._biasedBits.leadingZeroBitCount
) &>> 3
}
@inlinable
@inline(__always)
public func index(_ i: Index, offsetBy n: Int) -> Index {
let startOffset = distance(from: startIndex, to: i)
let newOffset = startOffset + n
_debugPrecondition(newOffset >= 0)
_debugPrecondition(newOffset <= count)
return Index(_biasedBits: _biasedBits._fullShiftRight(newOffset &<< 3))
}
}
extension _ValidUTF8Buffer: RangeReplaceableCollection {
@inlinable
public init() {
_biasedBits = 0
}
@inlinable
public var capacity: Int {
return _ValidUTF8Buffer.capacity
}
@inlinable
public static var capacity: Int {
return UInt32.bitWidth / Element.bitWidth
}
@inlinable
@inline(__always)
public mutating func append(_ e: Element) {
_debugPrecondition(count + 1 <= capacity)
_internalInvariant(
e != 192 && e != 193 && !(245...255).contains(e), "invalid UTF8 byte")
_biasedBits |= UInt32(e &+ 1) &<< (count &<< 3)
}
@inlinable
@inline(__always)
@discardableResult
public mutating func removeFirst() -> Element {
_debugPrecondition(!isEmpty)
let result = Element(truncatingIfNeeded: _biasedBits) &- 1
_biasedBits = _biasedBits._fullShiftRight(8)
return result
}
@inlinable
internal func _isValid(_ i: Index) -> Bool {
return i == endIndex || indices.contains(i)
}
@inlinable
@inline(__always)
public mutating func replaceSubrange<C: Collection>(
_ target: Range<Index>, with replacement: C
) where C.Element == Element {
_debugPrecondition(_isValid(target.lowerBound))
_debugPrecondition(_isValid(target.upperBound))
var r = _ValidUTF8Buffer()
for x in self[..<target.lowerBound] { r.append(x) }
for x in replacement { r.append(x) }
for x in self[target.upperBound...] { r.append(x) }
self = r
}
}
extension _ValidUTF8Buffer {
@inlinable
@inline(__always)
public mutating func append(contentsOf other: _ValidUTF8Buffer) {
_debugPrecondition(count + other.count <= capacity)
_biasedBits |= UInt32(
truncatingIfNeeded: other._biasedBits) &<< (count &<< 3)
}
}
extension _ValidUTF8Buffer {
@inlinable
public static var encodedReplacementCharacter: _ValidUTF8Buffer {
return _ValidUTF8Buffer(_biasedBits: 0xBD_BF_EF &+ 0x01_01_01)
}
@inlinable
internal var _bytes: (bytes: UInt64, count: Int) {
let count = self.count
let mask: UInt64 = 1 &<< (UInt64(truncatingIfNeeded: count) &<< 3) &- 1
let unbiased = UInt64(truncatingIfNeeded: _biasedBits) &- 0x0101010101010101
return (unbiased & mask, count)
}
}
|