File: Bits.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (110 lines) | stat: -rw-r--r-- 3,238 bytes parent folder | download
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
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2020 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation
import TSCBasic

struct Bits: RandomAccessCollection {
  var buffer: ByteString

  var startIndex: Int { return 0 }
  var endIndex: Int { return buffer.count * 8 }

  subscript(index: Int) -> UInt8 {
    let byte = buffer.contents[index / 8]
    return (byte >> UInt8(index % 8)) & 1
  }

  func readBits(atOffset offset: Int, count: Int) -> UInt64 {
    precondition(count >= 0 && count <= 64)
    precondition(offset >= 0)
    precondition(offset &+ count >= offset)
    precondition(offset &+ count <= self.endIndex)

    return buffer.contents.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
      let upperBound = offset &+ count
      let topByteIndex = upperBound >> 3
      var result: UInt64 = 0
      if upperBound & 7 != 0 {
        let mask: UInt8 = (1 << UInt8(upperBound & 7)) &- 1
        result = UInt64(bytes[topByteIndex] & mask)
      }
      for i in ((offset >> 3)..<(upperBound >> 3)).reversed() {
        result <<= 8
        result |= UInt64(bytes[i])
      }
      if offset & 7 != 0 {
        result >>= UInt64(offset & 7)
      }
      return result
    }
  }

  struct Cursor {
    enum Error: Swift.Error { case bufferOverflow }

    let buffer: Bits
    private var offset: Int = 0

    init(buffer: Bits) {
      self.buffer = buffer
    }
    
    init(buffer: ByteString) {
      self.init(buffer: Bits(buffer: buffer))
    }

    var isAtStart: Bool {
      return offset == buffer.startIndex
    }

    var isAtEnd: Bool {
      return offset == buffer.count
    }

    func peek(_ count: Int) throws -> UInt64 {
      if buffer.count - offset < count { throw Error.bufferOverflow }
      return buffer.readBits(atOffset: offset, count: count)
    }

    mutating func read(_ count: Int) throws -> UInt64 {
      defer { offset += count }
      return try peek(count)
    }

    mutating func read(bytes count: Int) throws -> ArraySlice<UInt8> {
      precondition(count >= 0)
      precondition(offset & 0b111 == 0)
      let newOffset = offset &+ (count << 3)
      precondition(newOffset >= offset)
      if newOffset > buffer.count { throw Error.bufferOverflow }
      defer { offset = newOffset }
      return buffer.buffer.contents.dropFirst(offset >> 3).prefix((newOffset - offset) >> 3)
    }

    mutating func skip(bytes count: Int) throws {
      precondition(count >= 0)
      precondition(offset & 0b111 == 0)
      let newOffset = offset &+ (count << 3)
      precondition(newOffset >= offset)
      if newOffset > buffer.count { throw Error.bufferOverflow }
      offset = newOffset
    }

    mutating func advance(toBitAlignment align: Int) throws {
      precondition(align > 0)
      precondition(offset &+ (align&-1) >= offset)
      precondition(align & (align &- 1) == 0)
      if offset % align == 0 { return }
      offset = (offset &+ align) & ~(align &- 1)
      if offset > buffer.count { throw Error.bufferOverflow }
    }
  }
}