-
Notifications
You must be signed in to change notification settings - Fork 13
/
xvarint.h
118 lines (105 loc) · 3.25 KB
/
xvarint.h
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
/**
\file xvarint.h
\brief 定义了 zig 、 zag 、 varint 相关操作。
\version 2.0.0.230227
\note For All
\author triones
\date 2017-09-01
\section history 版本记录
- 2017-09-05 添加 varint 实现。 1.0 。
- 2017-09-11 修正处理有符号时的错误。 1.0.1 。
- 2019-10-21 改进。1.1 。
- 2019-11-06 重构 zig 、 zag 。 1.2 。
- 2020-03-13 重构 varint 。 2.0 。
*/
#ifndef _XLIB_XVARINT_H_
#define _XLIB_XVARINT_H_
#include <array>
#include <climits>
#include <string>
namespace xlib {
/// zig 用于处理有符号数为无符号数,但返回还是原类型。
template <typename T> inline constexpr
std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>, T>
xzig(const T& v) {
if constexpr (std::is_signed_v<T>) {
// 有符号值,转换成无符号值。
return ((v << 1) ^ (v >> (sizeof(T) * CHAR_BIT - 1)));
} else {
// 无符号值或枚举值,不转换。
return v;
}
}
/// zag 根据输入类型,处理有符号数,返回还是原类型。
template <typename T> inline constexpr
std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>, T>
xzag(const T& v) {
if constexpr (std::is_signed_v<T>) {
// 有符号值,转换成有符号值。
return ((-(v & 0x01)) ^ ((v >> 1) & ~((T)1 << (sizeof(T) * CHAR_BIT - 1))));
} else {
// 无符号值,不转换。
return v;
}
}
template <typename T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>, int> = 0>
class xvarint : public std::array<uint8_t, sizeof(T) / CHAR_BIT + 1 + sizeof(T)> {
public:
using base = std::array<uint8_t, sizeof(T) / CHAR_BIT + 1 + sizeof(T)>;
private:
T _value;
public:
constexpr xvarint(const T& value)
: std::array<uint8_t, sizeof(T) / CHAR_BIT + 1 + sizeof(T)>(),
_value(value) {
// g++ 这里有 will be initialized after 警告,可忽略。
using U = typename std::make_unsigned_t<T>;
auto v = (U)xzig(value);
for (auto& pv : *this) {
const auto vv = (uint8_t)(v & 0x7F);
v >>= (CHAR_BIT - 1);
if (0 == v) {
pv = vv;
break;
}
pv = vv | 0x80;
}
}
constexpr uint8_t* data() const noexcept {
return (uint8_t*)base::data();
}
constexpr size_t size() const noexcept {
size_t n = 0;
for (const auto& v : *this) {
++n;
// g++ 这里有 may be used uninitialized in this function 警告,可忽略。
if (0 == (v & 0x80)) break;
}
return n;
}
constexpr operator T() const noexcept {
return _value;
}
constexpr T operator()() const noexcept {
return _value;
}
constexpr xvarint(const char* p) : _value(T()) {
using U = typename std::make_unsigned_t<T>;
U v = 0;
size_t count = 0;
for (auto& pv : *this) {
pv = *p;
++p;
v |= ((pv & 0x7F) << (count * (CHAR_BIT - 1)));
++count;
if (0 == (pv & 0x80)) {
_value = xzag((T)v);
break;
}
}
}
template <typename Ty, std::enable_if_t<(sizeof(Ty) == 1) || std::is_void<Ty>::value, int> = 0>
xvarint(const Ty* p) : xvarint((const char*)p) {}
};
} // namespace xlib
#endif // _XLIB_XVARINT_H_