]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/coding.h
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same 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 // Endian-neutral encoding:
11 // * Fixed-length numbers are encoded with least-significant byte first
12 // * In addition we support variable length "varint" encoding
13 // * Strings are encoded prefixed by their length in varint format
21 #include "rocksdb/write_batch.h"
22 #include "port/port.h"
24 // Some processors does not allow unaligned access to memory
26 #define PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED
31 // The maximum length of a varint in bytes for 64-bit.
32 const unsigned int kMaxVarint64Length
= 10;
34 // Standard Put... routines append to a string
35 extern void PutFixed32(std::string
* dst
, uint32_t value
);
36 extern void PutFixed64(std::string
* dst
, uint64_t value
);
37 extern void PutVarint32(std::string
* dst
, uint32_t value
);
38 extern void PutVarint32Varint32(std::string
* dst
, uint32_t value1
,
40 extern void PutVarint32Varint32Varint32(std::string
* dst
, uint32_t value1
,
41 uint32_t value2
, uint32_t value3
);
42 extern void PutVarint64(std::string
* dst
, uint64_t value
);
43 extern void PutVarint64Varint64(std::string
* dst
, uint64_t value1
,
45 extern void PutVarint32Varint64(std::string
* dst
, uint32_t value1
,
47 extern void PutVarint32Varint32Varint64(std::string
* dst
, uint32_t value1
,
48 uint32_t value2
, uint64_t value3
);
49 extern void PutLengthPrefixedSlice(std::string
* dst
, const Slice
& value
);
50 extern void PutLengthPrefixedSliceParts(std::string
* dst
,
51 const SliceParts
& slice_parts
);
53 // Standard Get... routines parse a value from the beginning of a Slice
54 // and advance the slice past the parsed value.
55 extern bool GetFixed64(Slice
* input
, uint64_t* value
);
56 extern bool GetFixed32(Slice
* input
, uint32_t* value
);
57 extern bool GetVarint32(Slice
* input
, uint32_t* value
);
58 extern bool GetVarint64(Slice
* input
, uint64_t* value
);
59 extern bool GetLengthPrefixedSlice(Slice
* input
, Slice
* result
);
60 // This function assumes data is well-formed.
61 extern Slice
GetLengthPrefixedSlice(const char* data
);
63 extern Slice
GetSliceUntil(Slice
* slice
, char delimiter
);
65 // Pointer-based variants of GetVarint... These either store a value
66 // in *v and return a pointer just past the parsed value, or return
67 // nullptr on error. These routines only look at bytes in the range
69 extern const char* GetVarint32Ptr(const char* p
,const char* limit
, uint32_t* v
);
70 extern const char* GetVarint64Ptr(const char* p
,const char* limit
, uint64_t* v
);
72 // Returns the length of the varint32 or varint64 encoding of "v"
73 extern int VarintLength(uint64_t v
);
75 // Lower-level versions of Put... that write directly into a character buffer
76 // REQUIRES: dst has enough space for the value being written
77 extern void EncodeFixed32(char* dst
, uint32_t value
);
78 extern void EncodeFixed64(char* dst
, uint64_t value
);
80 // Lower-level versions of Put... that write directly into a character buffer
81 // and return a pointer just past the last byte written.
82 // REQUIRES: dst has enough space for the value being written
83 extern char* EncodeVarint32(char* dst
, uint32_t value
);
84 extern char* EncodeVarint64(char* dst
, uint64_t value
);
86 // Lower-level versions of Get... that read directly from a character buffer
87 // without any bounds checking.
89 inline uint32_t DecodeFixed32(const char* ptr
) {
90 if (port::kLittleEndian
) {
93 memcpy(&result
, ptr
, sizeof(result
)); // gcc optimizes this to a plain load
96 return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr
[0])))
97 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr
[1])) << 8)
98 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr
[2])) << 16)
99 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr
[3])) << 24));
103 inline uint64_t DecodeFixed64(const char* ptr
) {
104 if (port::kLittleEndian
) {
105 // Load the raw bytes
107 memcpy(&result
, ptr
, sizeof(result
)); // gcc optimizes this to a plain load
110 uint64_t lo
= DecodeFixed32(ptr
);
111 uint64_t hi
= DecodeFixed32(ptr
+ 4);
112 return (hi
<< 32) | lo
;
116 // Internal routine for use by fallback path of GetVarint32Ptr
117 extern const char* GetVarint32PtrFallback(const char* p
,
120 inline const char* GetVarint32Ptr(const char* p
,
124 uint32_t result
= *(reinterpret_cast<const unsigned char*>(p
));
125 if ((result
& 128) == 0) {
130 return GetVarint32PtrFallback(p
, limit
, value
);
133 // -- Implementation of the functions declared above
134 inline void EncodeFixed32(char* buf
, uint32_t value
) {
135 if (port::kLittleEndian
) {
136 memcpy(buf
, &value
, sizeof(value
));
138 buf
[0] = value
& 0xff;
139 buf
[1] = (value
>> 8) & 0xff;
140 buf
[2] = (value
>> 16) & 0xff;
141 buf
[3] = (value
>> 24) & 0xff;
145 inline void EncodeFixed64(char* buf
, uint64_t value
) {
146 if (port::kLittleEndian
) {
147 memcpy(buf
, &value
, sizeof(value
));
149 buf
[0] = value
& 0xff;
150 buf
[1] = (value
>> 8) & 0xff;
151 buf
[2] = (value
>> 16) & 0xff;
152 buf
[3] = (value
>> 24) & 0xff;
153 buf
[4] = (value
>> 32) & 0xff;
154 buf
[5] = (value
>> 40) & 0xff;
155 buf
[6] = (value
>> 48) & 0xff;
156 buf
[7] = (value
>> 56) & 0xff;
160 // Pull the last 8 bits and cast it to a character
161 inline void PutFixed32(std::string
* dst
, uint32_t value
) {
162 if (port::kLittleEndian
) {
163 dst
->append(const_cast<const char*>(reinterpret_cast<char*>(&value
)),
166 char buf
[sizeof(value
)];
167 EncodeFixed32(buf
, value
);
168 dst
->append(buf
, sizeof(buf
));
172 inline void PutFixed64(std::string
* dst
, uint64_t value
) {
173 if (port::kLittleEndian
) {
174 dst
->append(const_cast<const char*>(reinterpret_cast<char*>(&value
)),
177 char buf
[sizeof(value
)];
178 EncodeFixed64(buf
, value
);
179 dst
->append(buf
, sizeof(buf
));
183 inline void PutVarint32(std::string
* dst
, uint32_t v
) {
185 char* ptr
= EncodeVarint32(buf
, v
);
186 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
189 inline void PutVarint32Varint32(std::string
* dst
, uint32_t v1
, uint32_t v2
) {
191 char* ptr
= EncodeVarint32(buf
, v1
);
192 ptr
= EncodeVarint32(ptr
, v2
);
193 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
196 inline void PutVarint32Varint32Varint32(std::string
* dst
, uint32_t v1
,
197 uint32_t v2
, uint32_t v3
) {
199 char* ptr
= EncodeVarint32(buf
, v1
);
200 ptr
= EncodeVarint32(ptr
, v2
);
201 ptr
= EncodeVarint32(ptr
, v3
);
202 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
205 inline char* EncodeVarint64(char* dst
, uint64_t v
) {
206 static const unsigned int B
= 128;
207 unsigned char* ptr
= reinterpret_cast<unsigned char*>(dst
);
209 *(ptr
++) = (v
& (B
- 1)) | B
;
212 *(ptr
++) = static_cast<unsigned char>(v
);
213 return reinterpret_cast<char*>(ptr
);
216 inline void PutVarint64(std::string
* dst
, uint64_t v
) {
218 char* ptr
= EncodeVarint64(buf
, v
);
219 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
222 inline void PutVarint64Varint64(std::string
* dst
, uint64_t v1
, uint64_t v2
) {
224 char* ptr
= EncodeVarint64(buf
, v1
);
225 ptr
= EncodeVarint64(ptr
, v2
);
226 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
229 inline void PutVarint32Varint64(std::string
* dst
, uint32_t v1
, uint64_t v2
) {
231 char* ptr
= EncodeVarint32(buf
, v1
);
232 ptr
= EncodeVarint64(ptr
, v2
);
233 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
236 inline void PutVarint32Varint32Varint64(std::string
* dst
, uint32_t v1
,
237 uint32_t v2
, uint64_t v3
) {
239 char* ptr
= EncodeVarint32(buf
, v1
);
240 ptr
= EncodeVarint32(ptr
, v2
);
241 ptr
= EncodeVarint64(ptr
, v3
);
242 dst
->append(buf
, static_cast<size_t>(ptr
- buf
));
245 inline void PutLengthPrefixedSlice(std::string
* dst
, const Slice
& value
) {
246 PutVarint32(dst
, static_cast<uint32_t>(value
.size()));
247 dst
->append(value
.data(), value
.size());
250 inline void PutLengthPrefixedSliceParts(std::string
* dst
,
251 const SliceParts
& slice_parts
) {
252 size_t total_bytes
= 0;
253 for (int i
= 0; i
< slice_parts
.num_parts
; ++i
) {
254 total_bytes
+= slice_parts
.parts
[i
].size();
256 PutVarint32(dst
, static_cast<uint32_t>(total_bytes
));
257 for (int i
= 0; i
< slice_parts
.num_parts
; ++i
) {
258 dst
->append(slice_parts
.parts
[i
].data(), slice_parts
.parts
[i
].size());
262 inline int VarintLength(uint64_t v
) {
271 inline bool GetFixed64(Slice
* input
, uint64_t* value
) {
272 if (input
->size() < sizeof(uint64_t)) {
275 *value
= DecodeFixed64(input
->data());
276 input
->remove_prefix(sizeof(uint64_t));
280 inline bool GetFixed32(Slice
* input
, uint32_t* value
) {
281 if (input
->size() < sizeof(uint32_t)) {
284 *value
= DecodeFixed32(input
->data());
285 input
->remove_prefix(sizeof(uint32_t));
289 inline bool GetVarint32(Slice
* input
, uint32_t* value
) {
290 const char* p
= input
->data();
291 const char* limit
= p
+ input
->size();
292 const char* q
= GetVarint32Ptr(p
, limit
, value
);
296 *input
= Slice(q
, static_cast<size_t>(limit
- q
));
301 inline bool GetVarint64(Slice
* input
, uint64_t* value
) {
302 const char* p
= input
->data();
303 const char* limit
= p
+ input
->size();
304 const char* q
= GetVarint64Ptr(p
, limit
, value
);
308 *input
= Slice(q
, static_cast<size_t>(limit
- q
));
313 // Provide an interface for platform independent endianness transformation
314 inline uint64_t EndianTransform(uint64_t input
, size_t size
) {
315 char* pos
= reinterpret_cast<char*>(&input
);
316 uint64_t ret_val
= 0;
317 for (size_t i
= 0; i
< size
; ++i
) {
318 ret_val
|= (static_cast<uint64_t>(static_cast<unsigned char>(pos
[i
]))
319 << ((size
- i
- 1) << 3));
324 inline bool GetLengthPrefixedSlice(Slice
* input
, Slice
* result
) {
326 if (GetVarint32(input
, &len
) && input
->size() >= len
) {
327 *result
= Slice(input
->data(), len
);
328 input
->remove_prefix(len
);
335 inline Slice
GetLengthPrefixedSlice(const char* data
) {
337 // +5: we assume "data" is not corrupted
338 // unsigned char is 7 bits, uint32_t is 32 bits, need 5 unsigned char
339 auto p
= GetVarint32Ptr(data
, data
+ 5 /* limit */, &len
);
340 return Slice(p
, len
);
343 inline Slice
GetSliceUntil(Slice
* slice
, char delimiter
) {
345 for (len
= 0; len
< slice
->size() && slice
->data()[len
] != delimiter
; ++len
) {
349 Slice
ret(slice
->data(), len
);
350 slice
->remove_prefix(len
+ ((len
< slice
->size()) ? 1 : 0));
355 inline void PutUnaligned(T
*memory
, const T
&value
) {
356 #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
357 char *nonAlignedMemory
= reinterpret_cast<char*>(memory
);
358 memcpy(nonAlignedMemory
, reinterpret_cast<const char*>(&value
), sizeof(T
));
365 inline void GetUnaligned(const T
*memory
, T
*value
) {
366 #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
367 char *nonAlignedMemory
= reinterpret_cast<char*>(value
);
368 memcpy(nonAlignedMemory
, reinterpret_cast<const char*>(memory
), sizeof(T
));
374 } // namespace rocksdb