/src/swift-nio/Sources/NIOCore/IntegerBitPacking.swift
Line | Count | Source (jump to first uncovered line) |
1 | | //===----------------------------------------------------------------------===// |
2 | | // |
3 | | // This source file is part of the SwiftNIO open source project |
4 | | // |
5 | | // Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors |
6 | | // Licensed under Apache License v2.0 |
7 | | // |
8 | | // See LICENSE.txt for license information |
9 | | // See CONTRIBUTORS.txt for the list of SwiftNIO project authors |
10 | | // |
11 | | // SPDX-License-Identifier: Apache-2.0 |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | // FIXME: Duplicated in NIO. |
16 | | |
17 | | @usableFromInline |
18 | | enum _IntegerBitPacking: Sendable {} |
19 | | |
20 | | extension _IntegerBitPacking { |
21 | | @inlinable |
22 | | static func packUU< |
23 | | Left: FixedWidthInteger & UnsignedInteger, |
24 | | Right: FixedWidthInteger & UnsignedInteger, |
25 | | Result: FixedWidthInteger & UnsignedInteger |
26 | | >( |
27 | | _ left: Left, |
28 | | _ right: Right, |
29 | | type: Result.Type = Result.self |
30 | 2.75G | ) -> Result { |
31 | 2.75G | assert(MemoryLayout<Left>.size + MemoryLayout<Right>.size <= MemoryLayout<Result>.size) |
32 | 2.75G | |
33 | 2.75G | let resultLeft = Result(left) |
34 | 2.75G | let resultRight = Result(right) |
35 | 2.75G | let result = (resultLeft << Right.bitWidth) | resultRight |
36 | 2.75G | assert(result.nonzeroBitCount == left.nonzeroBitCount + right.nonzeroBitCount) |
37 | 2.75G | return result |
38 | 2.75G | } |
39 | | |
40 | | @inlinable |
41 | | static func unpackUU< |
42 | | Input: FixedWidthInteger & UnsignedInteger, |
43 | | Left: FixedWidthInteger & UnsignedInteger, |
44 | | Right: FixedWidthInteger & UnsignedInteger |
45 | | >( |
46 | | _ input: Input, |
47 | | leftType: Left.Type = Left.self, |
48 | | rightType: Right.Type = Right.self |
49 | 1.78G | ) -> (Left, Right) { |
50 | 1.78G | assert(MemoryLayout<Left>.size + MemoryLayout<Right>.size <= MemoryLayout<Input>.size) |
51 | 1.78G | |
52 | 1.78G | let leftMask = Input(Left.max) |
53 | 1.78G | let rightMask = Input(Right.max) |
54 | 1.78G | let right = input & rightMask |
55 | 1.78G | let left = (input >> Right.bitWidth) & leftMask |
56 | 1.78G | |
57 | 1.78G | assert(input.nonzeroBitCount == left.nonzeroBitCount + right.nonzeroBitCount) |
58 | 1.78G | return (Left(left), Right(right)) |
59 | 1.78G | } |
60 | | } |
61 | | |
62 | | @usableFromInline |
63 | | enum IntegerBitPacking: Sendable {} |
64 | | |
65 | | extension IntegerBitPacking { |
66 | | @inlinable |
67 | 0 | static func packUInt32UInt16UInt8(_ left: UInt32, _ middle: UInt16, _ right: UInt8) -> UInt64 { |
68 | 0 | _IntegerBitPacking.packUU( |
69 | 0 | _IntegerBitPacking.packUU(right, middle, type: UInt32.self), |
70 | 0 | left |
71 | 0 | ) |
72 | 0 | } |
73 | | |
74 | | @inlinable |
75 | 0 | static func unpackUInt32UInt16UInt8(_ value: UInt64) -> (UInt32, UInt16, UInt8) { |
76 | 0 | let leftRight = _IntegerBitPacking.unpackUU(value, leftType: UInt32.self, rightType: UInt32.self) |
77 | 0 | let left = _IntegerBitPacking.unpackUU(leftRight.0, leftType: UInt8.self, rightType: UInt16.self) |
78 | 0 | return (leftRight.1, left.1, left.0) |
79 | 0 | } |
80 | | |
81 | | @inlinable |
82 | 0 | static func packUInt8UInt8(_ left: UInt8, _ right: UInt8) -> UInt16 { |
83 | 0 | _IntegerBitPacking.packUU(left, right) |
84 | 0 | } |
85 | | |
86 | | @inlinable |
87 | 0 | static func unpackUInt8UInt8(_ value: UInt16) -> (UInt8, UInt8) { |
88 | 0 | _IntegerBitPacking.unpackUU(value) |
89 | 0 | } |
90 | | |
91 | | @inlinable |
92 | 2.27G | static func packUInt16UInt8(_ left: UInt16, _ right: UInt8) -> UInt32 { |
93 | 2.27G | _IntegerBitPacking.packUU(left, right) |
94 | 2.27G | } |
95 | | |
96 | | @inlinable |
97 | 1.78G | static func unpackUInt16UInt8(_ value: UInt32) -> (UInt16, UInt8) { |
98 | 1.78G | _IntegerBitPacking.unpackUU(value) |
99 | 1.78G | } |
100 | | |
101 | | @inlinable |
102 | 0 | static func packUInt32CInt(_ left: UInt32, _ right: CInt) -> UInt64 { |
103 | 0 | _IntegerBitPacking.packUU(left, UInt32(truncatingIfNeeded: right)) |
104 | 0 | } |
105 | | |
106 | | @inlinable |
107 | 0 | static func unpackUInt32CInt(_ value: UInt64) -> (UInt32, CInt) { |
108 | 0 | let unpacked = _IntegerBitPacking.unpackUU(value, leftType: UInt32.self, rightType: UInt32.self) |
109 | 0 | return (unpacked.0, CInt(truncatingIfNeeded: unpacked.1)) |
110 | 0 | } |
111 | | } |