Varint.swift 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // Sources/SwiftProtobuf/Varint.swift - Varint encoding/decoding helpers
  2. //
  3. // Copyright (c) 2014 - 2016 Apple Inc. and the project authors
  4. // Licensed under Apache License v2.0 with Runtime Library Exception
  5. //
  6. // See LICENSE.txt for license information:
  7. // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
  8. //
  9. // -----------------------------------------------------------------------------
  10. ///
  11. /// Helper functions to varint-encode and decode integers.
  12. ///
  13. // -----------------------------------------------------------------------------
  14. /// Contains helper methods to varint-encode and decode integers.
  15. package enum Varint {
  16. /// Computes the number of bytes that would be needed to store a 32-bit varint.
  17. ///
  18. /// - Parameter value: The number whose varint size should be calculated.
  19. /// - Returns: The size, in bytes, of the 32-bit varint.
  20. @usableFromInline
  21. package static func encodedSize(of value: UInt32) -> Int {
  22. // This logic comes from the upstream C++ for CodedOutputStream::VarintSize32(uint32_t),
  23. // it provides a branchless calculation of the size.
  24. let clz = value.leadingZeroBitCount
  25. return ((UInt32.bitWidth &* 9 &+ 64) &- (clz &* 9)) / 64
  26. }
  27. /// Computes the number of bytes that would be needed to store a signed 32-bit varint, if it were
  28. /// treated as an unsigned integer with the same bit pattern.
  29. ///
  30. /// - Parameter value: The number whose varint size should be calculated.
  31. /// - Returns: The size, in bytes, of the 32-bit varint.
  32. @inline(__always)
  33. package static func encodedSize(of value: Int32) -> Int {
  34. // Must sign-extend.
  35. encodedSize(of: Int64(value))
  36. }
  37. /// Computes the number of bytes that would be needed to store a 64-bit varint.
  38. ///
  39. /// - Parameter value: The number whose varint size should be calculated.
  40. /// - Returns: The size, in bytes, of the 64-bit varint.
  41. @inline(__always)
  42. static func encodedSize(of value: Int64) -> Int {
  43. encodedSize(of: UInt64(bitPattern: value))
  44. }
  45. /// Computes the number of bytes that would be needed to store an unsigned 64-bit varint, if it
  46. /// were treated as a signed integer with the same bit pattern.
  47. ///
  48. /// - Parameter value: The number whose varint size should be calculated.
  49. /// - Returns: The size, in bytes, of the 64-bit varint.
  50. @usableFromInline
  51. static func encodedSize(of value: UInt64) -> Int {
  52. // This logic comes from the upstream C++ for CodedOutputStream::VarintSize64(uint64_t),
  53. // it provides a branchless calculation of the size.
  54. let clz = value.leadingZeroBitCount
  55. return ((UInt64.bitWidth &* 9 &+ 64) &- (clz &* 9)) / 64
  56. }
  57. /// Counts the number of distinct varints in a packed byte buffer.
  58. static func countVarintsInBuffer(start: UnsafeRawPointer, count: Int) -> Int {
  59. // We don't need to decode all the varints to count how many there
  60. // are. Just observe that every varint has exactly one byte with
  61. // value < 128. So we just count those...
  62. var n = 0
  63. var ints = 0
  64. while n < count {
  65. if start.load(fromByteOffset: n, as: UInt8.self) < 128 {
  66. ints &+= 1
  67. }
  68. n &+= 1
  69. }
  70. return ints
  71. }
  72. }