/src/rocksdb/util/coding.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | // |
6 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
7 | | // Use of this source code is governed by a BSD-style license that can be |
8 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
9 | | // |
10 | | // Encoding independent of machine byte order: |
11 | | // * Fixed-length numbers are encoded with least-significant byte first |
12 | | // (little endian, native order on Intel and others) |
13 | | // * In addition we support variable length "varint" encoding |
14 | | // * Strings are encoded prefixed by their length in varint format |
15 | | // |
16 | | // Some related functions are provided in coding_lean.h |
17 | | |
18 | | #pragma once |
19 | | #include <algorithm> |
20 | | #include <string> |
21 | | |
22 | | #include "port/port.h" |
23 | | #include "rocksdb/slice.h" |
24 | | #include "util/cast_util.h" |
25 | | #include "util/coding_lean.h" |
26 | | |
27 | | // Some processors does not allow unaligned access to memory |
28 | | #if defined(__sparc) |
29 | | #define PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED |
30 | | #endif |
31 | | |
32 | | namespace ROCKSDB_NAMESPACE { |
33 | | |
34 | | // The maximum length of a varint in bytes for 64-bit. |
35 | | const uint32_t kMaxVarint64Length = 10; |
36 | | |
37 | | // Standard Put... routines append to a string |
38 | | void PutFixed16(std::string* dst, uint16_t value); |
39 | | void PutFixed32(std::string* dst, uint32_t value); |
40 | | void PutFixed64(std::string* dst, uint64_t value); |
41 | | void PutVarint32(std::string* dst, uint32_t value); |
42 | | void PutVarint32Varint32(std::string* dst, uint32_t value1, uint32_t value2); |
43 | | void PutVarint32Varint32Varint32(std::string* dst, uint32_t value1, |
44 | | uint32_t value2, uint32_t value3); |
45 | | void PutVarint64(std::string* dst, uint64_t value); |
46 | | void PutVarint64Varint64(std::string* dst, uint64_t value1, uint64_t value2); |
47 | | void PutVarint32Varint64(std::string* dst, uint32_t value1, uint64_t value2); |
48 | | void PutVarint32Varint32Varint64(std::string* dst, uint32_t value1, |
49 | | uint32_t value2, uint64_t value3); |
50 | | void PutLengthPrefixedSlice(std::string* dst, const Slice& value); |
51 | | void PutLengthPrefixedSliceParts(std::string* dst, |
52 | | const SliceParts& slice_parts); |
53 | | void PutLengthPrefixedSlicePartsWithPadding(std::string* dst, |
54 | | const SliceParts& slice_parts, |
55 | | size_t pad_sz); |
56 | | |
57 | | // Standard Get... routines parse a value from the beginning of a Slice |
58 | | // and advance the slice past the parsed value. |
59 | | bool GetFixed64(Slice* input, uint64_t* value); |
60 | | bool GetFixed32(Slice* input, uint32_t* value); |
61 | | bool GetFixed16(Slice* input, uint16_t* value); |
62 | | bool GetVarint32(Slice* input, uint32_t* value); |
63 | | bool GetVarint64(Slice* input, uint64_t* value); |
64 | | bool GetVarsignedint64(Slice* input, int64_t* value); |
65 | | bool GetLengthPrefixedSlice(Slice* input, Slice* result); |
66 | | // This function assumes data is well-formed. |
67 | | Slice GetLengthPrefixedSlice(const char* data); |
68 | | |
69 | | Slice GetSliceUntil(Slice* slice, char delimiter); |
70 | | |
71 | | // Borrowed from |
72 | | // https://github.com/facebook/fbthrift/blob/449a5f77f9f9bae72c9eb5e78093247eef185c04/thrift/lib/cpp/util/VarintUtils-inl.h#L202-L208 |
73 | 3.95k | constexpr inline uint64_t i64ToZigzag(const int64_t l) { |
74 | 3.95k | return (static_cast<uint64_t>(l) << 1) ^ static_cast<uint64_t>(l >> 63); |
75 | 3.95k | } |
76 | 0 | inline int64_t zigzagToI64(uint64_t n) { |
77 | 0 | return (n >> 1) ^ -static_cast<int64_t>(n & 1); |
78 | 0 | } |
79 | | |
80 | | // Pointer-based variants of GetVarint... These either store a value |
81 | | // in *v and return a pointer just past the parsed value, or return |
82 | | // nullptr on error. These routines only look at bytes in the range |
83 | | // [p..limit-1] |
84 | | const char* GetVarint32Ptr(const char* p, const char* limit, uint32_t* v); |
85 | | const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* v); |
86 | | inline const char* GetVarsignedint64Ptr(const char* p, const char* limit, |
87 | 0 | int64_t* value) { |
88 | 0 | uint64_t u = 0; |
89 | 0 | const char* ret = GetVarint64Ptr(p, limit, &u); |
90 | 0 | *value = zigzagToI64(u); |
91 | 0 | return ret; |
92 | 0 | } |
93 | | |
94 | | // Returns the length of the varint32 or varint64 encoding of "v" |
95 | | int VarintLength(uint64_t v); |
96 | | |
97 | | // Lower-level versions of Put... that write directly into a character buffer |
98 | | // and return a pointer just past the last byte written. |
99 | | // REQUIRES: dst has enough space for the value being written |
100 | | char* EncodeVarint32(char* dst, uint32_t value); |
101 | | char* EncodeVarint64(char* dst, uint64_t value); |
102 | | |
103 | | // Internal routine for use by fallback path of GetVarint32Ptr |
104 | | const char* GetVarint32PtrFallback(const char* p, const char* limit, |
105 | | uint32_t* value); |
106 | | inline const char* GetVarint32Ptr(const char* p, const char* limit, |
107 | 37.5M | uint32_t* value) { |
108 | 37.5M | if (p < limit) { |
109 | 37.0M | uint32_t result = *(lossless_cast<const unsigned char*>(p)); |
110 | 37.0M | if ((result & 128) == 0) { |
111 | 34.0M | *value = result; |
112 | 34.0M | return p + 1; |
113 | 34.0M | } |
114 | 37.0M | } |
115 | 3.45M | return GetVarint32PtrFallback(p, limit, value); |
116 | 37.5M | } |
117 | | |
118 | | // Pull the last 8 bits and cast it to a character |
119 | 0 | inline void PutFixed16(std::string* dst, uint16_t value) { |
120 | 0 | if (port::kLittleEndian) { |
121 | 0 | dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)), |
122 | 0 | sizeof(value)); |
123 | 0 | } else { |
124 | 0 | char buf[sizeof(value)]; |
125 | 0 | EncodeFixed16(buf, value); |
126 | 0 | dst->append(buf, sizeof(buf)); |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | 392k | inline void PutFixed32(std::string* dst, uint32_t value) { |
131 | 392k | if (port::kLittleEndian) { |
132 | 392k | dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)), |
133 | 392k | sizeof(value)); |
134 | 392k | } else { |
135 | 0 | char buf[sizeof(value)]; |
136 | 0 | EncodeFixed32(buf, value); |
137 | 0 | dst->append(buf, sizeof(buf)); |
138 | 0 | } |
139 | 392k | } |
140 | | |
141 | 133M | inline void PutFixed64(std::string* dst, uint64_t value) { |
142 | 133M | if (port::kLittleEndian) { |
143 | 133M | dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)), |
144 | 133M | sizeof(value)); |
145 | 133M | } else { |
146 | 0 | char buf[sizeof(value)]; |
147 | 0 | EncodeFixed64(buf, value); |
148 | 0 | dst->append(buf, sizeof(buf)); |
149 | 0 | } |
150 | 133M | } |
151 | | |
152 | 4.61M | inline void PutVarint32(std::string* dst, uint32_t v) { |
153 | 4.61M | char buf[5]; |
154 | 4.61M | char* ptr = EncodeVarint32(buf, v); |
155 | 4.61M | dst->append(buf, static_cast<size_t>(ptr - buf)); |
156 | 4.61M | } |
157 | | |
158 | 216k | inline void PutVarint32Varint32(std::string* dst, uint32_t v1, uint32_t v2) { |
159 | 216k | char buf[10]; |
160 | 216k | char* ptr = EncodeVarint32(buf, v1); |
161 | 216k | ptr = EncodeVarint32(ptr, v2); |
162 | 216k | dst->append(buf, static_cast<size_t>(ptr - buf)); |
163 | 216k | } |
164 | | |
165 | | inline void PutVarint32Varint32Varint32(std::string* dst, uint32_t v1, |
166 | 1.08M | uint32_t v2, uint32_t v3) { |
167 | 1.08M | char buf[15]; |
168 | 1.08M | char* ptr = EncodeVarint32(buf, v1); |
169 | 1.08M | ptr = EncodeVarint32(ptr, v2); |
170 | 1.08M | ptr = EncodeVarint32(ptr, v3); |
171 | 1.08M | dst->append(buf, static_cast<size_t>(ptr - buf)); |
172 | 1.08M | } |
173 | | |
174 | 2.97M | inline char* EncodeVarint64(char* dst, uint64_t v) { |
175 | 2.97M | static const unsigned int B = 128; |
176 | 2.97M | unsigned char* ptr = lossless_cast<unsigned char*>(dst); |
177 | 4.25M | while (v >= B) { |
178 | 1.27M | *(ptr++) = (v & (B - 1)) | B; |
179 | 1.27M | v >>= 7; |
180 | 1.27M | } |
181 | 2.97M | *(ptr++) = static_cast<unsigned char>(v); |
182 | 2.97M | return lossless_cast<char*>(ptr); |
183 | 2.97M | } |
184 | | |
185 | 1.23M | inline void PutVarint64(std::string* dst, uint64_t v) { |
186 | 1.23M | char buf[kMaxVarint64Length]; |
187 | 1.23M | char* ptr = EncodeVarint64(buf, v); |
188 | 1.23M | dst->append(buf, static_cast<size_t>(ptr - buf)); |
189 | 1.23M | } |
190 | | |
191 | 3.95k | inline void PutVarsignedint64(std::string* dst, int64_t v) { |
192 | 3.95k | char buf[kMaxVarint64Length]; |
193 | | // Using Zigzag format to convert signed to unsigned |
194 | 3.95k | char* ptr = EncodeVarint64(buf, i64ToZigzag(v)); |
195 | 3.95k | dst->append(buf, static_cast<size_t>(ptr - buf)); |
196 | 3.95k | } |
197 | | |
198 | 211k | inline void PutVarint64Varint64(std::string* dst, uint64_t v1, uint64_t v2) { |
199 | 211k | char buf[20]; |
200 | 211k | char* ptr = EncodeVarint64(buf, v1); |
201 | 211k | ptr = EncodeVarint64(ptr, v2); |
202 | 211k | dst->append(buf, static_cast<size_t>(ptr - buf)); |
203 | 211k | } |
204 | | |
205 | 1.30M | inline void PutVarint32Varint64(std::string* dst, uint32_t v1, uint64_t v2) { |
206 | 1.30M | char buf[15]; |
207 | 1.30M | char* ptr = EncodeVarint32(buf, v1); |
208 | 1.30M | ptr = EncodeVarint64(ptr, v2); |
209 | 1.30M | dst->append(buf, static_cast<size_t>(ptr - buf)); |
210 | 1.30M | } |
211 | | |
212 | | inline void PutVarint32Varint32Varint64(std::string* dst, uint32_t v1, |
213 | 14.5k | uint32_t v2, uint64_t v3) { |
214 | 14.5k | char buf[20]; |
215 | 14.5k | char* ptr = EncodeVarint32(buf, v1); |
216 | 14.5k | ptr = EncodeVarint32(ptr, v2); |
217 | 14.5k | ptr = EncodeVarint64(ptr, v3); |
218 | 14.5k | dst->append(buf, static_cast<size_t>(ptr - buf)); |
219 | 14.5k | } |
220 | | |
221 | 3.24M | inline void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { |
222 | 3.24M | PutVarint32(dst, static_cast<uint32_t>(value.size())); |
223 | 3.24M | dst->append(value.data(), value.size()); |
224 | 3.24M | } |
225 | | |
226 | | inline void PutLengthPrefixedSliceParts(std::string* dst, size_t total_bytes, |
227 | 0 | const SliceParts& slice_parts) { |
228 | 0 | for (int i = 0; i < slice_parts.num_parts; ++i) { |
229 | 0 | total_bytes += slice_parts.parts[i].size(); |
230 | 0 | } |
231 | 0 | PutVarint32(dst, static_cast<uint32_t>(total_bytes)); |
232 | 0 | for (int i = 0; i < slice_parts.num_parts; ++i) { |
233 | 0 | dst->append(slice_parts.parts[i].data(), slice_parts.parts[i].size()); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | inline void PutLengthPrefixedSliceParts(std::string* dst, |
238 | 0 | const SliceParts& slice_parts) { |
239 | 0 | PutLengthPrefixedSliceParts(dst, /*total_bytes=*/0, slice_parts); |
240 | 0 | } |
241 | | |
242 | | inline void PutLengthPrefixedSlicePartsWithPadding( |
243 | 0 | std::string* dst, const SliceParts& slice_parts, size_t pad_sz) { |
244 | 0 | PutLengthPrefixedSliceParts(dst, /*total_bytes=*/pad_sz, slice_parts); |
245 | 0 | dst->append(pad_sz, '\0'); |
246 | 0 | } |
247 | | |
248 | 3.84M | inline int VarintLength(uint64_t v) { |
249 | 3.84M | int len = 1; |
250 | 4.11M | while (v >= 128) { |
251 | 269k | v >>= 7; |
252 | 269k | len++; |
253 | 269k | } |
254 | 3.84M | return len; |
255 | 3.84M | } |
256 | | |
257 | 154k | inline bool GetFixed64(Slice* input, uint64_t* value) { |
258 | 154k | if (input->size() < sizeof(uint64_t)) { |
259 | 0 | return false; |
260 | 0 | } |
261 | 154k | *value = DecodeFixed64(input->data()); |
262 | 154k | input->remove_prefix(sizeof(uint64_t)); |
263 | 154k | return true; |
264 | 154k | } |
265 | | |
266 | 375k | inline bool GetFixed32(Slice* input, uint32_t* value) { |
267 | 375k | if (input->size() < sizeof(uint32_t)) { |
268 | 0 | return false; |
269 | 0 | } |
270 | 375k | *value = DecodeFixed32(input->data()); |
271 | 375k | input->remove_prefix(sizeof(uint32_t)); |
272 | 375k | return true; |
273 | 375k | } |
274 | | |
275 | 0 | inline bool GetFixed16(Slice* input, uint16_t* value) { |
276 | 0 | if (input->size() < sizeof(uint16_t)) { |
277 | 0 | return false; |
278 | 0 | } |
279 | 0 | *value = DecodeFixed16(input->data()); |
280 | 0 | input->remove_prefix(sizeof(uint16_t)); |
281 | 0 | return true; |
282 | 0 | } |
283 | | |
284 | 11.8M | inline bool GetVarint32(Slice* input, uint32_t* value) { |
285 | 11.8M | const char* p = input->data(); |
286 | 11.8M | const char* limit = p + input->size(); |
287 | 11.8M | const char* q = GetVarint32Ptr(p, limit, value); |
288 | 11.8M | if (q == nullptr) { |
289 | 476k | return false; |
290 | 11.3M | } else { |
291 | 11.3M | *input = Slice(q, static_cast<size_t>(limit - q)); |
292 | 11.3M | return true; |
293 | 11.3M | } |
294 | 11.8M | } |
295 | | |
296 | 4.98M | inline bool GetVarint64(Slice* input, uint64_t* value) { |
297 | 4.98M | const char* p = input->data(); |
298 | 4.98M | const char* limit = p + input->size(); |
299 | 4.98M | const char* q = GetVarint64Ptr(p, limit, value); |
300 | 4.98M | if (q == nullptr) { |
301 | 0 | return false; |
302 | 4.98M | } else { |
303 | 4.98M | *input = Slice(q, static_cast<size_t>(limit - q)); |
304 | 4.98M | return true; |
305 | 4.98M | } |
306 | 4.98M | } |
307 | | |
308 | 0 | inline bool GetVarsignedint64(Slice* input, int64_t* value) { |
309 | 0 | const char* p = input->data(); |
310 | 0 | const char* limit = p + input->size(); |
311 | 0 | const char* q = GetVarsignedint64Ptr(p, limit, value); |
312 | 0 | if (q == nullptr) { |
313 | 0 | return false; |
314 | 0 | } else { |
315 | 0 | *input = Slice(q, static_cast<size_t>(limit - q)); |
316 | 0 | return true; |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | 6.89M | inline bool GetLengthPrefixedSlice(Slice* input, Slice* result) { |
321 | 6.89M | uint32_t len = 0; |
322 | 6.89M | if (GetVarint32(input, &len) && input->size() >= len) { |
323 | 6.89M | *result = Slice(input->data(), len); |
324 | 6.89M | input->remove_prefix(len); |
325 | 6.89M | return true; |
326 | 6.89M | } else { |
327 | 0 | return false; |
328 | 0 | } |
329 | 6.89M | } |
330 | | |
331 | 25.0M | inline Slice GetLengthPrefixedSlice(const char* data) { |
332 | 25.0M | uint32_t len = 0; |
333 | | // +5: we assume "data" is not corrupted |
334 | | // unsigned char is 7 bits, uint32_t is 32 bits, need 5 unsigned char |
335 | 25.0M | auto p = GetVarint32Ptr(data, data + 5 /* limit */, &len); |
336 | 25.0M | return Slice(p, len); |
337 | 25.0M | } |
338 | | |
339 | 0 | inline Slice GetSliceUntil(Slice* slice, char delimiter) { |
340 | 0 | uint32_t len = 0; |
341 | 0 | for (len = 0; len < slice->size() && slice->data()[len] != delimiter; ++len) { |
342 | 0 | // nothing |
343 | 0 | } |
344 | 0 |
|
345 | 0 | Slice ret(slice->data(), len); |
346 | 0 | slice->remove_prefix(len + ((len < slice->size()) ? 1 : 0)); |
347 | 0 | return ret; |
348 | 0 | } |
349 | | |
350 | | template <class T> |
351 | | #ifdef ROCKSDB_UBSAN_RUN |
352 | | #if defined(__clang__) |
353 | | __attribute__((__no_sanitize__("alignment"))) |
354 | | #elif defined(__GNUC__) |
355 | | __attribute__((__no_sanitize_undefined__)) |
356 | | #endif |
357 | | #endif |
358 | | inline void |
359 | 6.94M | PutUnaligned(T* memory, const T& value) { |
360 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) |
361 | | char* nonAlignedMemory = reinterpret_cast<char*>(memory); |
362 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(&value), sizeof(T)); |
363 | | #else |
364 | 6.94M | *memory = value; |
365 | 6.94M | #endif |
366 | 6.94M | } void rocksdb::PutUnaligned<long>(long*, long const&) Line | Count | Source | 359 | 146k | PutUnaligned(T* memory, const T& value) { | 360 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) | 361 | | char* nonAlignedMemory = reinterpret_cast<char*>(memory); | 362 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(&value), sizeof(T)); | 363 | | #else | 364 | 146k | *memory = value; | 365 | 146k | #endif | 366 | 146k | } |
void rocksdb::PutUnaligned<unsigned long>(unsigned long*, unsigned long const&) Line | Count | Source | 359 | 6.80M | PutUnaligned(T* memory, const T& value) { | 360 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) | 361 | | char* nonAlignedMemory = reinterpret_cast<char*>(memory); | 362 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(&value), sizeof(T)); | 363 | | #else | 364 | 6.80M | *memory = value; | 365 | 6.80M | #endif | 366 | 6.80M | } |
Unexecuted instantiation: void rocksdb::PutUnaligned<unsigned int>(unsigned int*, unsigned int const&) |
367 | | |
368 | | template <class T> |
369 | | #ifdef ROCKSDB_UBSAN_RUN |
370 | | #if defined(__clang__) |
371 | | __attribute__((__no_sanitize__("alignment"))) |
372 | | #elif defined(__GNUC__) |
373 | | __attribute__((__no_sanitize_undefined__)) |
374 | | #endif |
375 | | #endif |
376 | | inline void |
377 | 28.2M | GetUnaligned(const T* memory, T* value) { |
378 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) |
379 | | char* nonAlignedMemory = reinterpret_cast<char*>(value); |
380 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(memory), sizeof(T)); |
381 | | #else |
382 | 28.2M | *value = *memory; |
383 | 28.2M | #endif |
384 | 28.2M | } void rocksdb::GetUnaligned<long>(long const*, long*) Line | Count | Source | 377 | 585k | GetUnaligned(const T* memory, T* value) { | 378 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) | 379 | | char* nonAlignedMemory = reinterpret_cast<char*>(value); | 380 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(memory), sizeof(T)); | 381 | | #else | 382 | 585k | *value = *memory; | 383 | 585k | #endif | 384 | 585k | } |
void rocksdb::GetUnaligned<unsigned long>(unsigned long const*, unsigned long*) Line | Count | Source | 377 | 27.6M | GetUnaligned(const T* memory, T* value) { | 378 | | #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED) | 379 | | char* nonAlignedMemory = reinterpret_cast<char*>(value); | 380 | | memcpy(nonAlignedMemory, reinterpret_cast<const char*>(memory), sizeof(T)); | 381 | | #else | 382 | 27.6M | *value = *memory; | 383 | 27.6M | #endif | 384 | 27.6M | } |
Unexecuted instantiation: void rocksdb::GetUnaligned<unsigned int>(unsigned int const*, unsigned int*) |
385 | | |
386 | | } // namespace ROCKSDB_NAMESPACE |