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).
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.
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
16 // Some related functions are provided in coding_lean.h
22 #include "port/port.h"
23 #include "rocksdb/slice.h"
24 #include "util/coding_lean.h"
26 // Some processors does not allow unaligned access to memory
28 #define PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED
31 namespace ROCKSDB_NAMESPACE
{
33 // The maximum length of a varint in bytes for 64-bit.
34 const unsigned int kMaxVarint64Length
= 10;
36 // Standard Put... routines append to a string
37 extern void PutFixed16(std::string
* dst
, uint16_t value
);
38 extern void PutFixed32(std::string
* dst
, uint32_t value
);
39 extern void PutFixed64(std::string
* dst
, uint64_t value
);
40 extern void PutVarint32(std::string
* dst
, uint32_t value
);
41 extern void PutVarint32Varint32(std::string
* dst
, uint32_t value1
,
43 extern void PutVarint32Varint32Varint32(std::string
* dst
, uint32_t value1
,
44 uint32_t value2
, uint32_t value3
);
45 extern void PutVarint64(std::string
* dst
, uint64_t value
);
46 extern void PutVarint64Varint64(std::string
* dst
, uint64_t value1
,
48 extern void PutVarint32Varint64(std::string
* dst
, uint32_t value1
,
50 extern void PutVarint32Varint32Varint64(std::string
* dst
, uint32_t value1
,
51 uint32_t value2
, uint64_t value3
);
52 extern void PutLengthPrefixedSlice(std::string
* dst
, const Slice
& value
);
53 extern void PutLengthPrefixedSliceParts(std::string
* dst
,
54 const SliceParts
& slice_parts
);
55 extern void PutLengthPrefixedSlicePartsWithPadding(
56 std::string
* dst
, const SliceParts
& slice_parts
, size_t pad_sz
);
58 // Standard Get... routines parse a value from the beginning of a Slice
59 // and advance the slice past the parsed value.
60 extern bool GetFixed64(Slice
* input
, uint64_t* value
);
61 extern bool GetFixed32(Slice
* input
, uint32_t* value
);
62 extern bool GetFixed16(Slice
* input
, uint16_t* value
);
63 extern bool GetVarint32(Slice
* input
, uint32_t* value
);
64 extern bool GetVarint64(Slice
* input
, uint64_t* value
);
65 extern bool GetVarsignedint64(Slice
* input
, int64_t* value
);
66 extern bool GetLengthPrefixedSlice(Slice
* input
, Slice
* result
);
67 // This function assumes data is well-formed.
68 extern Slice
GetLengthPrefixedSlice(const char* data
);
70 extern Slice
GetSliceUntil(Slice
* slice
, char delimiter
);
73 // https://github.com/facebook/fbthrift/blob/449a5f77f9f9bae72c9eb5e78093247eef185c04/thrift/lib/cpp/util/VarintUtils-inl.h#L202-L208
74 constexpr inline uint64_t i64ToZigzag(const int64_t l
) {
75 return (static_cast<uint64_t>(l
) << 1) ^ static_cast<uint64_t>(l
>> 63);
77 inline int64_t zigzagToI64(uint64_t n
) {
78 return (n
>> 1) ^ -static_cast<int64_t>(n
& 1);
81 // Pointer-based variants of GetVarint... These either store a value
82 // in *v and return a pointer just past the parsed value, or return
83 // nullptr on error. These routines only look at bytes in the range
85 extern const char* GetVarint32Ptr(const char* p
,const char* limit
, uint32_t* v
);
86 extern const char* GetVarint64Ptr(const char* p
,const char* limit
, uint64_t* v
);
87 inline const char* GetVarsignedint64Ptr(const char* p
, const char* limit
,
90 const char* ret
= GetVarint64Ptr(p
, limit
, &u
);
91 *value
= zigzagToI64(u
);
95 // Returns the length of the varint32 or varint64 encoding of "v"
96 extern int VarintLength(uint64_t v
);
98 // Lower-level versions of Put... that write directly into a character buffer
99 // and return a pointer just past the last byte written.
100 // REQUIRES: dst has enough space for the value being written
101 extern char* EncodeVarint32(char* dst
, uint32_t value
);
102 extern char* EncodeVarint64(char* dst
, uint64_t value
);
104 // Internal routine for use by fallback path of GetVarint32Ptr
105 extern const char* GetVarint32PtrFallback(const char* p
,
108 inline const char* GetVarint32Ptr(const char* p
,
112 uint32_t result
= *(reinterpret_cast<const unsigned char*>(p
));
113 if ((result
& 128) == 0) {
118 return GetVarint32PtrFallback(p
, limit
, value
);
121 // Pull the last 8 bits and cast it to a character
122 inline void PutFixed16(std::string
* dst
, uint16_t value
) {
123 if (port::kLittleEndian
) {
124 dst
->append(const_cast<const char*>(reinterpret_cast<char*>(&value
)),
127 char buf
[sizeof(value
)];
128 EncodeFixed16(buf
, value
);
129 dst
->append(buf
, sizeof(buf
));
133 inline void PutFixed32(std::string
* dst
, uint32_t value
) {
134 if (port::kLittleEndian
) {
135 dst
->append(const_cast<const char*>(reinterpret_cast<char*>(&value
)),
138 char buf
[sizeof(value
)];
139 EncodeFixed32(buf
, value
);
140 dst
->append(buf
, sizeof(buf
));
144 inline void PutFixed64(std::string
* dst
, uint64_t value
) {
145 if (port::kLittleEndian
) {
146 dst
->append(const_cast<const char*>(reinterpret_cast<char*>(&value
)),
149 char buf
[sizeof(value
)];
150 EncodeFixed64(buf
, value
);
151 dst
->append(buf
, sizeof(buf
));
155 inline void PutVarint32(std::string
* dst
, uint32_t v
) {
157 char* ptr
= EncodeVarint32(buf
, v
);
158 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
161 inline void PutVarint32Varint32(std::string
* dst
, uint32_t v1
, uint32_t v2
) {
163 char* ptr
= EncodeVarint32(buf
, v1
);
164 ptr
= EncodeVarint32(ptr
, v2
);
165 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
168 inline void PutVarint32Varint32Varint32(std::string
* dst
, uint32_t v1
,
169 uint32_t v2
, uint32_t v3
) {
171 char* ptr
= EncodeVarint32(buf
, v1
);
172 ptr
= EncodeVarint32(ptr
, v2
);
173 ptr
= EncodeVarint32(ptr
, v3
);
174 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
177 inline char* EncodeVarint64(char* dst
, uint64_t v
) {
178 static const unsigned int B
= 128;
179 unsigned char* ptr
= reinterpret_cast<unsigned char*>(dst
);
181 *(ptr
++) = (v
& (B
- 1)) | B
;
184 *(ptr
++) = static_cast<unsigned char>(v
);
185 return reinterpret_cast<char*>(ptr
);
188 inline void PutVarint64(std::string
* dst
, uint64_t v
) {
189 char buf
[kMaxVarint64Length
];
190 char* ptr
= EncodeVarint64(buf
, v
);
191 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
194 inline void PutVarsignedint64(std::string
* dst
, int64_t v
) {
195 char buf
[kMaxVarint64Length
];
196 // Using Zigzag format to convert signed to unsigned
197 char* ptr
= EncodeVarint64(buf
, i64ToZigzag(v
));
198 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
201 inline void PutVarint64Varint64(std::string
* dst
, uint64_t v1
, uint64_t v2
) {
203 char* ptr
= EncodeVarint64(buf
, v1
);
204 ptr
= EncodeVarint64(ptr
, v2
);
205 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
208 inline void PutVarint32Varint64(std::string
* dst
, uint32_t v1
, uint64_t v2
) {
210 char* ptr
= EncodeVarint32(buf
, v1
);
211 ptr
= EncodeVarint64(ptr
, v2
);
212 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
215 inline void PutVarint32Varint32Varint64(std::string
* dst
, uint32_t v1
,
216 uint32_t v2
, uint64_t v3
) {
218 char* ptr
= EncodeVarint32(buf
, v1
);
219 ptr
= EncodeVarint32(ptr
, v2
);
220 ptr
= EncodeVarint64(ptr
, v3
);
221 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
224 inline void PutLengthPrefixedSlice(std::string
* dst
, const Slice
& value
) {
225 PutVarint32(dst
, static_cast<uint32_t>(value
.size()));
226 dst
->append(value
.data(), value
.size());
229 inline void PutLengthPrefixedSliceParts(std::string
* dst
, size_t total_bytes
,
230 const SliceParts
& slice_parts
) {
231 for (int i
= 0; i
< slice_parts
.num_parts
; ++i
) {
232 total_bytes
+= slice_parts
.parts
[i
].size();
234 PutVarint32(dst
, static_cast<uint32_t>(total_bytes
));
235 for (int i
= 0; i
< slice_parts
.num_parts
; ++i
) {
236 dst
->append(slice_parts
.parts
[i
].data(), slice_parts
.parts
[i
].size());
240 inline void PutLengthPrefixedSliceParts(std::string
* dst
,
241 const SliceParts
& slice_parts
) {
242 PutLengthPrefixedSliceParts(dst
, /*total_bytes=*/0, slice_parts
);
245 inline void PutLengthPrefixedSlicePartsWithPadding(
246 std::string
* dst
, const SliceParts
& slice_parts
, size_t pad_sz
) {
247 PutLengthPrefixedSliceParts(dst
, /*total_bytes=*/pad_sz
, slice_parts
);
248 dst
->append(pad_sz
, '\0');
251 inline int VarintLength(uint64_t v
) {
260 inline bool GetFixed64(Slice
* input
, uint64_t* value
) {
261 if (input
->size() < sizeof(uint64_t)) {
264 *value
= DecodeFixed64(input
->data());
265 input
->remove_prefix(sizeof(uint64_t));
269 inline bool GetFixed32(Slice
* input
, uint32_t* value
) {
270 if (input
->size() < sizeof(uint32_t)) {
273 *value
= DecodeFixed32(input
->data());
274 input
->remove_prefix(sizeof(uint32_t));
278 inline bool GetFixed16(Slice
* input
, uint16_t* value
) {
279 if (input
->size() < sizeof(uint16_t)) {
282 *value
= DecodeFixed16(input
->data());
283 input
->remove_prefix(sizeof(uint16_t));
287 inline bool GetVarint32(Slice
* input
, uint32_t* value
) {
288 const char* p
= input
->data();
289 const char* limit
= p
+ input
->size();
290 const char* q
= GetVarint32Ptr(p
, limit
, value
);
294 *input
= Slice(q
, static_cast<size_t>(limit
- q
));
299 inline bool GetVarint64(Slice
* input
, uint64_t* value
) {
300 const char* p
= input
->data();
301 const char* limit
= p
+ input
->size();
302 const char* q
= GetVarint64Ptr(p
, limit
, value
);
306 *input
= Slice(q
, static_cast<size_t>(limit
- q
));
311 inline bool GetVarsignedint64(Slice
* input
, int64_t* value
) {
312 const char* p
= input
->data();
313 const char* limit
= p
+ input
->size();
314 const char* q
= GetVarsignedint64Ptr(p
, limit
, value
);
318 *input
= Slice(q
, static_cast<size_t>(limit
- q
));
323 // Swaps between big and little endian. Can be used to in combination
324 // with the little-endian encoding/decoding functions to encode/decode
326 template <typename T
>
327 inline T
EndianSwapValue(T v
) {
328 static_assert(std::is_integral
<T
>::value
, "non-integral type");
331 if (sizeof(T
) == 2) {
332 return static_cast<T
>(_byteswap_ushort(static_cast<uint16_t>(v
)));
333 } else if (sizeof(T
) == 4) {
334 return static_cast<T
>(_byteswap_ulong(static_cast<uint32_t>(v
)));
335 } else if (sizeof(T
) == 8) {
336 return static_cast<T
>(_byteswap_uint64(static_cast<uint64_t>(v
)));
339 if (sizeof(T
) == 2) {
340 return static_cast<T
>(__builtin_bswap16(static_cast<uint16_t>(v
)));
341 } else if (sizeof(T
) == 4) {
342 return static_cast<T
>(__builtin_bswap32(static_cast<uint32_t>(v
)));
343 } else if (sizeof(T
) == 8) {
344 return static_cast<T
>(__builtin_bswap64(static_cast<uint64_t>(v
)));
347 // Recognized by clang as bswap, but not by gcc :(
349 for (size_t i
= 0; i
< sizeof(T
); ++i
) {
350 ret_val
|= ((v
>> (8 * i
)) & 0xff) << (8 * (sizeof(T
) - 1 - i
));
355 inline bool GetLengthPrefixedSlice(Slice
* input
, Slice
* result
) {
357 if (GetVarint32(input
, &len
) && input
->size() >= len
) {
358 *result
= Slice(input
->data(), len
);
359 input
->remove_prefix(len
);
366 inline Slice
GetLengthPrefixedSlice(const char* data
) {
368 // +5: we assume "data" is not corrupted
369 // unsigned char is 7 bits, uint32_t is 32 bits, need 5 unsigned char
370 auto p
= GetVarint32Ptr(data
, data
+ 5 /* limit */, &len
);
371 return Slice(p
, len
);
374 inline Slice
GetSliceUntil(Slice
* slice
, char delimiter
) {
376 for (len
= 0; len
< slice
->size() && slice
->data()[len
] != delimiter
; ++len
) {
380 Slice
ret(slice
->data(), len
);
381 slice
->remove_prefix(len
+ ((len
< slice
->size()) ? 1 : 0));
386 #ifdef ROCKSDB_UBSAN_RUN
387 #if defined(__clang__)
388 __attribute__((__no_sanitize__("alignment")))
389 #elif defined(__GNUC__)
390 __attribute__((__no_sanitize_undefined__
))
393 inline void PutUnaligned(T
*memory
, const T
&value
) {
394 #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
395 char *nonAlignedMemory
= reinterpret_cast<char*>(memory
);
396 memcpy(nonAlignedMemory
, reinterpret_cast<const char*>(&value
), sizeof(T
));
403 #ifdef ROCKSDB_UBSAN_RUN
404 #if defined(__clang__)
405 __attribute__((__no_sanitize__("alignment")))
406 #elif defined(__GNUC__)
407 __attribute__((__no_sanitize_undefined__
))
410 inline void GetUnaligned(const T
*memory
, T
*value
) {
411 #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
412 char *nonAlignedMemory
= reinterpret_cast<char*>(value
);
413 memcpy(nonAlignedMemory
, reinterpret_cast<const char*>(memory
), sizeof(T
));
419 } // namespace ROCKSDB_NAMESPACE