Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
varint.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
8{
9
10auto varint::encode(uint64_t value) -> std::vector<uint8_t>
11{
12 if (value <= max_1byte)
13 {
14 // 6-bit: prefix 0b00
15 return {static_cast<uint8_t>(value)};
16 }
17
18 if (value <= max_2byte)
19 {
20 // 14-bit: prefix 0b01
21 return {
22 static_cast<uint8_t>(prefix_2byte | ((value >> 8) & value_mask)),
23 static_cast<uint8_t>(value & 0xFF)
24 };
25 }
26
27 if (value <= max_4byte)
28 {
29 // 30-bit: prefix 0b10
30 return {
31 static_cast<uint8_t>(prefix_4byte | ((value >> 24) & value_mask)),
32 static_cast<uint8_t>((value >> 16) & 0xFF),
33 static_cast<uint8_t>((value >> 8) & 0xFF),
34 static_cast<uint8_t>(value & 0xFF)
35 };
36 }
37
38 // 62-bit: prefix 0b11
39 // Clamp to max if exceeding varint_max
40 if (value > varint_max)
41 {
42 value = varint_max;
43 }
44
45 return {
46 static_cast<uint8_t>(prefix_8byte | ((value >> 56) & value_mask)),
47 static_cast<uint8_t>((value >> 48) & 0xFF),
48 static_cast<uint8_t>((value >> 40) & 0xFF),
49 static_cast<uint8_t>((value >> 32) & 0xFF),
50 static_cast<uint8_t>((value >> 24) & 0xFF),
51 static_cast<uint8_t>((value >> 16) & 0xFF),
52 static_cast<uint8_t>((value >> 8) & 0xFF),
53 static_cast<uint8_t>(value & 0xFF)
54 };
55}
56
57auto varint::encode_with_length(uint64_t value, size_t min_length)
59{
60 // Validate min_length
61 if (min_length != 1 && min_length != 2 && min_length != 4 && min_length != 8)
62 {
65 "Invalid minimum length",
66 "quic::varint",
67 "min_length must be 1, 2, 4, or 8"
68 );
69 }
70
71 // Check if value fits in the requested length
72 uint64_t max_for_length = 0;
73 switch (min_length)
74 {
75 case 1: max_for_length = max_1byte; break;
76 case 2: max_for_length = max_2byte; break;
77 case 4: max_for_length = max_4byte; break;
78 case 8: max_for_length = max_8byte; break;
79 default: break;
80 }
81
82 // Find the actual minimum length needed
83 size_t actual_length = encoded_length(value);
84
85 // Use the larger of the two
86 size_t use_length = (min_length > actual_length) ? min_length : actual_length;
87
88 // If the requested min_length is smaller than needed, the value won't fit
89 // But we use the larger length, so this is fine
90
91 // Check if value exceeds maximum encodable
92 if (value > varint_max)
93 {
96 "Value exceeds maximum",
97 "quic::varint",
98 "Value exceeds 2^62 - 1"
99 );
100 }
101
102 // Encode with the determined length
103 std::vector<uint8_t> result;
104 switch (use_length)
105 {
106 case 1:
107 result = {static_cast<uint8_t>(value)};
108 break;
109
110 case 2:
111 result = {
112 static_cast<uint8_t>(prefix_2byte | ((value >> 8) & value_mask)),
113 static_cast<uint8_t>(value & 0xFF)
114 };
115 break;
116
117 case 4:
118 result = {
119 static_cast<uint8_t>(prefix_4byte | ((value >> 24) & value_mask)),
120 static_cast<uint8_t>((value >> 16) & 0xFF),
121 static_cast<uint8_t>((value >> 8) & 0xFF),
122 static_cast<uint8_t>(value & 0xFF)
123 };
124 break;
125
126 case 8:
127 result = {
128 static_cast<uint8_t>(prefix_8byte | ((value >> 56) & value_mask)),
129 static_cast<uint8_t>((value >> 48) & 0xFF),
130 static_cast<uint8_t>((value >> 40) & 0xFF),
131 static_cast<uint8_t>((value >> 32) & 0xFF),
132 static_cast<uint8_t>((value >> 24) & 0xFF),
133 static_cast<uint8_t>((value >> 16) & 0xFF),
134 static_cast<uint8_t>((value >> 8) & 0xFF),
135 static_cast<uint8_t>(value & 0xFF)
136 };
137 break;
138
139 default:
140 break;
141 }
142
143 return ok(std::move(result));
144}
145
146auto varint::decode(std::span<const uint8_t> data)
148{
149 if (data.empty())
150 {
153 "Empty buffer",
154 "quic::varint",
155 "Cannot decode from empty buffer"
156 );
157 }
158
159 const uint8_t first_byte = data[0];
160 const size_t length = length_from_prefix(first_byte);
161
162 if (data.size() < length)
163 {
166 "Insufficient data",
167 "quic::varint",
168 "Buffer too small for encoded length"
169 );
170 }
171
172 uint64_t value = first_byte & value_mask;
173
174 for (size_t i = 1; i < length; ++i)
175 {
176 value = (value << 8) | data[i];
177 }
178
179 return ok(std::make_pair(value, length));
180}
181
182} // namespace kcenon::network::protocols::quic
static auto encode(uint64_t value) -> std::vector< uint8_t >
Encode a value to variable-length format.
Definition varint.cpp:10
static auto decode(std::span< const uint8_t > data) -> Result< std::pair< uint64_t, size_t > >
Decode variable-length integer from buffer.
Definition varint.cpp:146
static auto encode_with_length(uint64_t value, size_t min_length) -> Result< std::vector< uint8_t > >
Encode with minimum length requirement.
Definition varint.cpp:57
@ error
Black hole detected, reset to base.
constexpr uint64_t varint_max
Maximum value that can be encoded in QUIC variable-length integer.
Definition varint.h:21
VoidResult ok()