forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvle.hh
133 lines (119 loc) · 4.32 KB
/
vle.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* Copyright (C) 2021 ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#pragma once
#include <seastar/core/bitops.hh>
#include <seastar/core/byteorder.hh>
namespace utils {
/*
* The express encoder below is optimized to encode a value
* that may only have non-zeroes in its first 12 bits
*/
static constexpr size_t uleb64_express_bits = 12;
static constexpr uint32_t uleb64_express_supreme = 1 << uleb64_express_bits;
// Returns the number of bytes needed to encode the value
// The value cannot be 0 (not checked)
inline size_t uleb64_encoded_size(uint32_t val) noexcept {
return seastar::log2floor(val) / 6 + 1;
}
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline void uleb64_encode(char*& pos, uint32_t val, Poison&& poison, Unpoison&& unpoison) noexcept {
uint64_t b = 64;
auto start = pos;
do {
b |= val & 63;
val >>= 6;
if (!val) {
b |= 128;
}
unpoison(pos, 1);
*pos++ = b;
b = 0;
} while (val);
poison(start, pos - start);
}
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline void uleb64_encode(char*& pos, uint32_t val, size_t encoded_size, Poison&& poison, Unpoison&& unpoison) noexcept {
uint64_t b = 64;
auto start = pos;
unpoison(start, encoded_size);
do {
b |= val & 63;
val >>= 6;
if (!--encoded_size) {
b |= 128;
}
*pos++ = b;
b = 0;
} while (encoded_size);
poison(start, pos - start);
}
#if !defined(SEASTAR_ASAN_ENABLED)
inline void uleb64_express_encode_impl(char*& pos, uint64_t val, size_t size) noexcept {
static_assert(uleb64_express_bits == 12);
if (size > sizeof(uint64_t)) {
static uint64_t zero = 0;
std::copy_n(reinterpret_cast<char*>(&zero), sizeof(zero), pos + size - sizeof(uint64_t));
}
seastar::write_le(pos, uint64_t(((val & 0xfc0) << 2) | ((val & 0x3f) | 64)));
pos += size;
pos[-1] |= 0x80;
}
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline void uleb64_express_encode(char*& pos, uint32_t val, size_t encoded_size, size_t gap, Poison&& poison, Unpoison&& unpoison) noexcept {
if (encoded_size + gap > sizeof(uint64_t)) {
uleb64_express_encode_impl(pos, val, encoded_size);
} else {
uleb64_encode(pos, val, encoded_size, poison, unpoison);
}
}
#else
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline void uleb64_express_encode(char*& pos, uint32_t val, size_t encoded_size, size_t gap, Poison&& poison, Unpoison&& unpoison) noexcept {
uleb64_encode(pos, val, encoded_size, poison, unpoison);
}
#endif
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline uint32_t uleb64_decode_forwards(const char*& pos, Poison&& poison, Unpoison&& unpoison) noexcept {
uint32_t n = 0;
unsigned shift = 0;
auto p = pos; // avoid aliasing; p++ doesn't touch memory
uint8_t b;
do {
unpoison(p, 1);
b = *p++;
if (shift < 32) {
// non-canonical encoding can cause large shift; undefined in C++
n |= uint32_t(b & 63) << shift;
}
shift += 6;
} while ((b & 128) == 0);
poison(pos, p - pos);
pos = p;
return n;
}
template <typename Poison, typename Unpoison>
requires std::is_invocable<Poison, const char*, size_t>::value && std::is_invocable<Unpoison, const char*, size_t>::value
inline uint32_t uleb64_decode_bacwards(const char*& pos, Poison&& poison, Unpoison&& unpoison) noexcept {
uint32_t n = 0;
uint8_t b;
auto p = pos; // avoid aliasing; --p doesn't touch memory
do {
--p;
unpoison(p, 1);
b = *p;
n = (n << 6) | (b & 63);
} while ((b & 64) == 0);
poison(p, pos - p);
pos = p;
return n;
}
} // namespace utils