Coverage Report

Created: 2025-07-23 07:17

/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