/src/swift-protobuf/Sources/SwiftProtobuf/Varint.swift
Line | Count | Source |
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 | | |
15 | | /// Contains helper methods to varint-encode and decode integers. |
16 | | package enum Varint { |
17 | | |
18 | | /// Computes the number of bytes that would be needed to store a 32-bit varint. |
19 | | /// |
20 | | /// - Parameter value: The number whose varint size should be calculated. |
21 | | /// - Returns: The size, in bytes, of the 32-bit varint. |
22 | | @usableFromInline |
23 | 2.36M | package static func encodedSize(of value: UInt32) -> Int { |
24 | 2.36M | // This logic comes from the upstream C++ for CodedOutputStream::VarintSize32(uint32_t), |
25 | 2.36M | // it provides a branchless calculation of the size. |
26 | 2.36M | let clz = value.leadingZeroBitCount |
27 | 2.36M | return ((UInt32.bitWidth &* 9 &+ 64) &- (clz &* 9)) / 64 |
28 | 2.36M | } |
29 | | |
30 | | /// Computes the number of bytes that would be needed to store a signed 32-bit varint, if it were |
31 | | /// treated as an unsigned integer with the same bit pattern. |
32 | | /// |
33 | | /// - Parameter value: The number whose varint size should be calculated. |
34 | | /// - Returns: The size, in bytes, of the 32-bit varint. |
35 | | @inline(__always) |
36 | 292k | package static func encodedSize(of value: Int32) -> Int { |
37 | 292k | // Must sign-extend. |
38 | 292k | encodedSize(of: Int64(value)) |
39 | 292k | } |
40 | | |
41 | | /// Computes the number of bytes that would be needed to store a 64-bit varint. |
42 | | /// |
43 | | /// - Parameter value: The number whose varint size should be calculated. |
44 | | /// - Returns: The size, in bytes, of the 64-bit varint. |
45 | | @inline(__always) |
46 | 33.2k | static func encodedSize(of value: Int64) -> Int { |
47 | 33.2k | encodedSize(of: UInt64(bitPattern: value)) |
48 | 33.2k | } |
49 | | |
50 | | /// Computes the number of bytes that would be needed to store an unsigned 64-bit varint, if it |
51 | | /// were treated as a signed integer with the same bit pattern. |
52 | | /// |
53 | | /// - Parameter value: The number whose varint size should be calculated. |
54 | | /// - Returns: The size, in bytes, of the 64-bit varint. |
55 | | @usableFromInline |
56 | 3.68M | static func encodedSize(of value: UInt64) -> Int { |
57 | 3.68M | // This logic comes from the upstream C++ for CodedOutputStream::VarintSize64(uint64_t), |
58 | 3.68M | // it provides a branchless calculation of the size. |
59 | 3.68M | let clz = value.leadingZeroBitCount |
60 | 3.68M | return ((UInt64.bitWidth &* 9 &+ 64) &- (clz &* 9)) / 64 |
61 | 3.68M | } |
62 | | |
63 | | /// Counts the number of distinct varints in a packed byte buffer. |
64 | 7 | static func countVarintsInBuffer(start: UnsafeRawPointer, count: Int) -> Int { |
65 | 7 | // We don't need to decode all the varints to count how many there |
66 | 7 | // are. Just observe that every varint has exactly one byte with |
67 | 7 | // value < 128. So we just count those... |
68 | 7 | var n = 0 |
69 | 7 | var ints = 0 |
70 | 214 | while n < count { |
71 | 207 | if start.load(fromByteOffset: n, as: UInt8.self) < 128 { |
72 | 188 | ints &+= 1 |
73 | 188 | } |
74 | 207 | n &+= 1 |
75 | 207 | } |
76 | 7 | return ints |
77 | 7 | } |
78 | | } |