-
Notifications
You must be signed in to change notification settings - Fork 0
/
kvarint.h
112 lines (96 loc) · 6.36 KB
/
kvarint.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
// SPDX-LICENSE-IDENTIFIER: MIT
#ifndef _KVARINT_H__
#define _KVARINT_H__
#include <stdint.h>
#include <stdlib.h>
#include "macro.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
KVARINT_OK = 0,
KVARINT_DECODE_BUF_SHORT,
KVARINT_DECODE_BUF_INVALID,
} kvarint_errcode_en;
#define KVARINT_DECL_DECODE_FUNC_(bits_) \
kvarint_errcode_en kvarint_decode##bits_( \
void const *buf, \
size_t buf_size, \
size_t *out_len, \
uint##bits_##_t *out \
)
KVARINT_DECL_DECODE_FUNC_(64);
KVARINT_DECL_DECODE_FUNC_(32);
KVARINT_DECL_DECODE_FUNC_(16);
KVARINT_DECL_DECODE_FUNC_(8);
#define KVARINT_DECL_DECODE_FUNC_SIGNED_(bits_) \
INLINE kvarint_errcode_en kvarint_decode##bits_##s( \
void const *buf, \
size_t buf_size, \
size_t *out_len, \
int##bits_##_t *out \
) \
{ \
/* Explain this to uint_*_t * to avoid right shift be a arithemetic shift \
* that leave the most significant bit(MSB) no change. \
* \
* since encode use left shift, it is a logic shift that fill the MSB with \
* 0, we must be also ensure the right shift operation be a logic shift. \
*/ \
uint##bits_##_t *p = (uint##bits_##_t *)out; \
const kvarint_errcode_en ret = kvarint_decode##bits_(buf, buf_size, out_len, p); \
\
/* *p = (p is odd) ? (*p+1) / 2 : p / 2; */ \
*p = (*p & 1) ? ~((*p - 1) >> 1) : (*p >> 1); \
return ret; \
}
KVARINT_DECL_DECODE_FUNC_SIGNED_(64)
KVARINT_DECL_DECODE_FUNC_SIGNED_(32)
KVARINT_DECL_DECODE_FUNC_SIGNED_(16)
KVARINT_DECL_DECODE_FUNC_SIGNED_(8)
#define KVARINT_DEF_BUF_STRUCT_(bits_, max_bytes_) \
typedef struct { \
char buf[max_bytes_]; \
size_t len; \
} kvarint_buf##bits_##_t
KVARINT_DEF_BUF_STRUCT_(64, 10);
KVARINT_DEF_BUF_STRUCT_(32, 5);
KVARINT_DEF_BUF_STRUCT_(16, 3);
KVARINT_DEF_BUF_STRUCT_(8, 1);
#define KVARINT_DECL_ENCODE_FUNC_(bits_) \
void kvarint_encode##bits_(uint##bits_##_t num, kvarint_buf##bits_##_t *buf);
KVARINT_DECL_ENCODE_FUNC_(64);
KVARINT_DECL_ENCODE_FUNC_(32);
KVARINT_DECL_ENCODE_FUNC_(16);
KVARINT_DECL_ENCODE_FUNC_(8);
#define KVARINT_DECL_ENCODE_FUNC_SIGNED_(bits_) \
INLINE void kvarint_encode##bits_##s(int##bits_##_t num, kvarint_buf##bits_##_t *buf) \
{ \
/* Since -1 is (~0), ie. the maximum number of uint_*_t, \
* it will be encoded to 10 bytes of uint64_t. \
* \
* However, user want the -1 also be encoded to 1 bytes like 1. \
* For other negative whose absolute value is small, also be encoded to \
* same bytes with their absolute. \
* \
* Algorithm: \
* Distribute the negative and positive to the odd and even number \
* in the uint_*_t range. \
* \
* In this way, -1 can be encoded to 1 bytes since it is mapped to 1. \
* \
* \see https://github.com/dominictarr/signed-varint \
*/ \
\
/* num = (num < 0) ? (num * -2 - 1) : (num * 2) */ \
num = (num & ((uint##bits_##_t)(1) << ((bits_)-1))) ? (((~num) << 1) + 1) : (num << 1); \
kvarint_encode##bits_((uint##bits_##_t)num, buf); \
}
KVARINT_DECL_ENCODE_FUNC_SIGNED_(64)
KVARINT_DECL_ENCODE_FUNC_SIGNED_(32)
KVARINT_DECL_ENCODE_FUNC_SIGNED_(16)
KVARINT_DECL_ENCODE_FUNC_SIGNED_(8)
#ifdef __cplusplus
} //! extern "C"
#endif
#endif // !_KVARINT_H__