Skip to content

Commit 2931937

Browse files
committed
feat: Support big-endian platform
1 parent ea3e233 commit 2931937

7 files changed

+229
-34
lines changed

endian_api.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef KVARINT_ENDIAN_API_H__
2+
#define KVARINT_ENDIAN_API_H__
3+
4+
#include "platform_macro.h"
5+
6+
#ifdef KVARINT_ON_WIN
7+
# include "endian_api_win.h"
8+
#elif defined(KVARINT_ON_UNIX)
9+
# include "endian_api_linux.h"
10+
#endif
11+
12+
#endif

endian_api_linux.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef KVARINT_ENDIAN_API_H
2+
#define KVARINT_ENDIAN_API_H
3+
4+
#include <stdint.h>
5+
#include <endian.h>
6+
#include "macro.h"
7+
8+
// network byte order conversion function
9+
10+
/**
11+
* To network byte order
12+
*/
13+
inline uint8_t kvarint_ToNetworkByteOrder8(uint8_t host8) { return host8; }
14+
inline uint16_t kvarint_ToNetworkByteOrder16(uint16_t host16) { return htobe16(host16); }
15+
inline uint32_t kvarint_ToNetworkByteOrder32(uint32_t host32) { return htobe32(host32); }
16+
inline uint64_t kvarint_ToNetworkByteOrder64(uint64_t host64) { return htobe64(host64); }
17+
18+
/**
19+
* To host byte order
20+
*/
21+
inline uint8_t kvarint_ToHostByteOrder8(uint8_t net8) { return net8; }
22+
inline uint16_t kvarint_ToHostByteOrder16(uint16_t net16) { return be16toh(net16); }
23+
inline uint32_t kvarint_ToHostByteOrder32(uint32_t net32) { return be32toh(net32); }
24+
inline uint64_t kvarint_ToHostByteOrder64(uint64_t net64) { return be64toh(net64); }
25+
26+
#endif

endian_api_win.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef KVARINT_WIN_CORE_UTIL_ENDIAN_API_H_
2+
#define KVARINT_WIN_CORE_UTIL_ENDIAN_API_H_
3+
4+
#include <winsock2.h>
5+
#include <stdint.h>
6+
#include "macro.h"
7+
8+
// network byte order conversion function
9+
10+
/**
11+
* To network byte order
12+
*/
13+
inline uint8_t kvarint_ToNetworkByteOrder8(uint8_t host8) { return host8; }
14+
inline uint16_t kvarint_ToNetworkByteOrder16(uint16_t host16) { return htons(host16); }
15+
inline uint32_t kvarint_ToNetworkByteOrder32(uint32_t host32) { return htonl(host32); }
16+
inline uint64_t kvarint_ToNetworkByteOrder64(uint64_t host64) { return htonll(host64); }
17+
18+
/**
19+
* To host byte order
20+
*/
21+
inline uint8_t kvarint_ToHostByteOrder8(uint8_t net8) { return net8; }
22+
inline uint16_t kvarint_ToHostByteOrder16(uint16_t net16) { return ntohs(net16); }
23+
inline uint32_t kvarint_ToHostByteOrder32(uint32_t net32) { return ntohl(net32); }
24+
inline uint64_t kvarint_ToHostByteOrder64(uint64_t net64) { return ntohll(net64); }
25+
26+
#endif

kvarint.c

+31-7
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,39 @@
33

44
#include <assert.h>
55
#include <stdio.h>
6+
#include <string.h>
7+
#include <stdbool.h>
8+
9+
#include "./endian_api.h"
10+
11+
inline static bool is_machine_litte_endian()
12+
{
13+
static int n = 1;
14+
return (*(char *)&n == 1);
15+
}
616

717
#define DEF_ENCODE_FUNC_(bits_, num_t_, buf_t_) \
818
void kvarint_encode##bits_(num_t_ num, buf_t_ *buf) \
919
{ \
1020
int idx = 0; \
11-
while (num > 127) { \
12-
buf->buf[idx++] = 0x80 | ((uint8_t)num & 0x7f); \
13-
num >>= 7; \
21+
if (!is_machine_litte_endian()) { \
22+
idx = sizeof(buf->buf) - 1; \
23+
while (num > 127) { \
24+
buf->buf[idx--] = 0x80 | ((uint8_t)num & 0x7f); \
25+
num >>= 7; \
26+
} \
27+
buf->buf[idx] = 0x80 | num; \
28+
buf->buf[sizeof(buf->buf) - 1] &= 0x7f; \
29+
buf->len = sizeof(buf->buf) - idx; \
30+
memmove(buf->buf, &buf->buf[idx], buf->len); \
31+
} else { \
32+
while (num > 127) { \
33+
buf->buf[idx++] = 0x80 | ((uint8_t)num & 0x7f); \
34+
num >>= 7; \
35+
} \
36+
buf->buf[idx] = num; \
37+
buf->len = idx + 1; \
1438
} \
15-
buf->buf[idx] = num; \
16-
buf->len = idx + 1; \
1739
}
1840

1941
#define DEF_ENCODE_FUNC2_(bits_) DEF_ENCODE_FUNC_(bits_, uint##bits_##_t, kvarint_buf##bits_##_t)
@@ -45,12 +67,14 @@ DEF_ENCODE_FUNC2_(64)
4567
shift += 7; \
4668
if (!(buf8[idx] & 0x80)) { \
4769
*out_len = idx + 1; \
70+
if (!is_machine_litte_endian()) { \
71+
*out = kvarint_ToNetworkByteOrder64(*out); \
72+
} \
4873
return KVARINT_OK; \
4974
} \
5075
if (shift > 63) return KVARINT_DECODE_BUF_INVALID; \
5176
++idx; \
5277
} \
53-
\
5478
return KVARINT_DECODE_BUF_SHORT; \
5579
}
5680

@@ -70,4 +94,4 @@ kvarint_errcode_en kvarint_decode8(void const *buf, size_t len, size_t *out_len,
7094
DEF_DECODE_FUNC_(64)
7195
DEF_DECODE_FUNC_(32)
7296
DEF_DECODE_FUNC_(16)
73-
// DEF_DECODE_FUNC_(8)
97+
// DEF_DECODE_FUNC_(8)

kvarint.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#define _KVARINT_H__
44

55
#include <stdint.h>
6-
#include <stdio.h>
76
#include <stdlib.h>
87

98
#include "macro.h"
@@ -70,7 +69,7 @@ KVARINT_DEF_BUF_STRUCT_(16, 3);
7069
KVARINT_DEF_BUF_STRUCT_(8, 1);
7170

7271
#define KVARINT_DECL_ENCODE_FUNC_(bits_) \
73-
void kvarint_encode##bits_(uint##bits_##_t num, kvarint_buf##bits_##_t *buf)
72+
void kvarint_encode##bits_(uint##bits_##_t num, kvarint_buf##bits_##_t *buf);
7473

7574
KVARINT_DECL_ENCODE_FUNC_(64);
7675
KVARINT_DECL_ENCODE_FUNC_(32);

platform_macro.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef KVARINT_UTIL_PLATFORM_MACRO_H__
2+
#define KVARINT_UTIL_PLATFORM_MACRO_H__
3+
4+
#ifdef __linux__
5+
# define KVARINT_ON_LINUX 1
6+
#endif
7+
8+
#if defined(_WIN32)
9+
# define KVARINT_ON_WIN 1
10+
#endif
11+
12+
#if (defined(__unix__) || defined(__linux__)) && !defined(KVARINT_TEST_THREAD)
13+
# define KVARINT_ON_UNIX 1
14+
#endif
15+
16+
#define _XKEYCHECK_H
17+
#ifndef _WINSOCKAPI_
18+
// #define _WINSOCKAPI_
19+
#endif
20+
21+
#endif

test.cc

+112-25
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,49 @@
33
#include <gtest/gtest.h>
44
#include <random>
55

6-
#define DEF_TEST_FUNC1(bytes_) \
7-
kvarint_buf64_t buf64; \
8-
uint64_t in = 1; \
9-
in <<= (7 * ((bytes_)-1)); \
10-
in += 123; \
11-
kvarint_encode64(in, &buf64); \
12-
ASSERT_EQ(buf64.len, (bytes_)); \
13-
\
14-
uint64_t out64; \
15-
size_t len = 0; \
16-
ASSERT_EQ(KVARINT_OK, kvarint_decode64(buf64.buf, buf64.len, &len, &out64)); \
17-
\
18-
ASSERT_EQ(in, out64)
6+
#include "endian_api.h"
7+
8+
extern void kvarint_encode64be(uint64_t num, kvarint_buf64_t *buf);
9+
extern kvarint_errcode_en kvarint_decode64be(
10+
void const *buf,
11+
size_t len,
12+
size_t *out_len,
13+
uint64_t *out
14+
);
15+
16+
void print_bits(uint64_t n)
17+
{
18+
for (size_t i = 0; i < sizeof(n) * 8; ++i) {
19+
std::cout << ((n & (1 << (sizeof(n) * 8 - 1 - i))) > 0 ? 1 : 0);
20+
}
21+
std::cout << '\n';
22+
}
23+
24+
#define DEF_TEST_FUNC1(bytes_) \
25+
kvarint_buf64_t buf64; \
26+
uint64_t in = 1; \
27+
\
28+
in <<= (7 * ((bytes_)-1)); \
29+
in += 123; \
30+
kvarint_encode64(in, &buf64); \
31+
ASSERT_EQ(buf64.len, (bytes_)); \
32+
\
33+
uint64_t out64; \
34+
size_t len = 0; \
35+
ASSERT_EQ(KVARINT_OK, kvarint_decode64(buf64.buf, buf64.len, &len, &out64)); \
36+
ASSERT_EQ(in, out64); \
37+
in = kvarint_ToNetworkByteOrder64(in); \
38+
kvarint_encode64be(in, &buf64); \
39+
ASSERT_EQ(buf64.len, (bytes_)); \
40+
ASSERT_EQ(KVARINT_OK, kvarint_decode64be(buf64.buf, buf64.len, &len, &out64)); \
41+
print_bits(in); \
42+
print_bits(out64); \
43+
ASSERT_EQ(in, out64) << "decode be error"; \
44+
ASSERT_EQ(len, buf64.len) << "decode be len error";
1945

2046
TEST(kvarint, encode_and_decode1)
2147
{
22-
size_t len = 0;
48+
size_t len = 0;
2349
kvarint_buf32_t buf32;
2450
kvarint_encode32(123, &buf32);
2551
ASSERT_EQ(buf32.len, 1);
@@ -42,12 +68,12 @@ TEST(kvarint, encode_and_decode10) { DEF_TEST_FUNC1(10); }
4268

4369
TEST(kvarint, encode_and_decode_large_data)
4470
{
45-
kvarint_buf64_t buf;
46-
uint64_t out;
47-
uint64_t N = 1000000;
71+
kvarint_buf64_t buf;
72+
uint64_t out;
73+
uint64_t N = 1000000;
4874
std::uniform_int_distribution<uint64_t> uid(0, (uint64_t)-1);
49-
std::default_random_engine dre(time(NULL));
50-
size_t len = 0;
75+
std::default_random_engine dre(time(NULL));
76+
size_t len = 0;
5177
for (uint64_t i = 0; i < N; ++i) {
5278
auto r = uid(dre);
5379
kvarint_encode64(r, &buf);
@@ -58,16 +84,77 @@ TEST(kvarint, encode_and_decode_large_data)
5884

5985
TEST(kvarint, encode_and_decode_large_data_sign)
6086
{
61-
kvarint_buf64_t buf;
62-
int64_t out;
63-
int64_t N = 1000000;
87+
kvarint_buf64_t buf;
88+
int64_t out;
89+
int64_t N = 1000000;
6490
std::uniform_int_distribution<int64_t> uid(-INT64_MAX, INT64_MAX);
65-
std::default_random_engine dre(time(NULL));
66-
size_t len;
67-
for (int64_t i = -N; i < 0; ++i) {
91+
std::default_random_engine dre(time(NULL));
92+
size_t len;
93+
for (int64_t i = 0; i < N; ++i) {
6894
auto r = uid(dre);
6995
kvarint_encode64s(r, &buf);
7096
kvarint_decode64s(buf.buf, buf.len, &len, &out);
7197
ASSERT_EQ(r, out) << "i = " << i;
7298
}
7399
}
100+
101+
TEST(kvarint, signed_example)
102+
{
103+
kvarint_buf64_t buf;
104+
int64_t out;
105+
size_t len;
106+
kvarint_encode64s(1, &buf);
107+
kvarint_decode64s(buf.buf, buf.len, &len, &out);
108+
109+
ASSERT_EQ(1, out) << out;
110+
}
111+
112+
void kvarint_encode64be(uint64_t num, kvarint_buf64_t *buf)
113+
{
114+
// int idx = sizeof(buf->buf) - 1;
115+
int idx = 0;
116+
printf("Encode num = %lu\n", num);
117+
printf("Encode num(le) = %lu\n", kvarint_ToHostByteOrder64(num));
118+
119+
while (kvarint_ToHostByteOrder64(num) > 127) {
120+
buf->buf[idx++] = uint8_t(0x80) | ((uint8_t)(num >> 56) & uint8_t(0x7f));
121+
printf("Encode buf[%d] = 0x%x\n", idx - 1, (uint8_t)buf->buf[idx - 1]);
122+
printf(
123+
"Correct Encode = 0x%x\n",
124+
uint8_t(0x80) | ((uint8_t)(kvarint_ToHostByteOrder64(num)) & uint8_t(0x7f))
125+
);
126+
num = kvarint_ToNetworkByteOrder64(kvarint_ToHostByteOrder64(num) >> 7);
127+
printf("num = %lu\n", num);
128+
printf("num(le) = %lu\n", kvarint_ToHostByteOrder64(num));
129+
}
130+
buf->buf[idx] = uint8_t(num >> 56);
131+
printf("last encode = 0x%x\n", buf->buf[idx]);
132+
printf("Correct last encode(le) = %lu\n", kvarint_ToHostByteOrder64(num));
133+
/* buf->buf[sizeof(buf->buf) - 1] &= uint8_t(0x7f); */
134+
/* memmove(buf->buf, &buf->buf[idx], buf->len); */
135+
/* buf->len = sizeof(buf->buf) - idx; */
136+
buf->len = idx + 1;
137+
}
138+
139+
kvarint_errcode_en kvarint_decode64be(void const *buf, size_t len, size_t *out_len, uint64_t *out)
140+
{
141+
assert(out);
142+
assert(out_len);
143+
144+
int idx = 0;
145+
uint8_t const *buf8 = (uint8_t const *)buf;
146+
int shift = 0;
147+
*out = 0;
148+
while (idx < len) {
149+
*out |= ((uint64_t)(buf8[idx] & uint8_t(0x7f))) << shift;
150+
shift += 7;
151+
if (!(buf8[idx] & uint8_t(0x80))) {
152+
*out_len = idx + 1;
153+
*out = kvarint_ToNetworkByteOrder64(*out);
154+
return KVARINT_OK;
155+
}
156+
if (shift > 63) return KVARINT_DECODE_BUF_INVALID;
157+
++idx;
158+
}
159+
return KVARINT_DECODE_BUF_SHORT;
160+
}

0 commit comments

Comments
 (0)