~bigbes/tarantool

tarantool-protobuf

ref: c77ecc62ad571ab1f5abfae7cde31f006399804a tarantool-protobuf/bench/c_accel/prim.c -rw-r--r-- 2.4 KiB
c77ecc62 — Eugene Blikh codegen: inline 1+2-byte varint fast path in packed-scalar decode inner loop (ozn) 2 months ago
                                                                                
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
/*
 * prim.c -- per-primitive wire helpers exposed via plain C ABI.
 *
 * Strategy 2 of tarantool-protobuf-04c. Lua-side dispatch stays in
 * Lua (read t.name, t.age, ... via t-table accesses), but each
 * wire-format primitive crosses the FFI boundary.
 *
 * Compile as a shared lib loaded by ffi.load() -- not luaopen_*.
 */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#if defined(_WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif

/* ibuf shape mirrors the FFI cdef in prim_ffi.lua. */
typedef struct ibuf_s {
	uint8_t *data;
	size_t   len;
	size_t   cap;
} ibuf_t;

EXPORT void
pb_ibuf_init(ibuf_t *b)
{
	b->cap = 4096;
	b->data = (uint8_t *)malloc(b->cap);
	b->len = 0;
}

EXPORT void
pb_ibuf_free(ibuf_t *b)
{
	free(b->data);
	b->data = NULL;
	b->cap = 0;
	b->len = 0;
}

EXPORT void
pb_ibuf_reset(ibuf_t *b)
{
	b->len = 0;
}

static void
pb_ibuf_grow(ibuf_t *b, size_t need)
{
	size_t nc = b->cap;
	while (nc < b->len + need)
		nc *= 2;
	b->data = (uint8_t *)realloc(b->data, nc);
	b->cap = nc;
}

static inline void
pb_ibuf_reserve(ibuf_t *b, size_t need)
{
	if (b->len + need > b->cap)
		pb_ibuf_grow(b, need);
}

/* ---------------------------------------------------------------- *
 *  Primitives.                                                     *
 * ---------------------------------------------------------------- */

EXPORT void
pb_write_varint(ibuf_t *b, uint64_t v)
{
	pb_ibuf_reserve(b, 10);
	while (v >= 0x80) {
		b->data[b->len++] = (uint8_t)(v | 0x80);
		v >>= 7;
	}
	b->data[b->len++] = (uint8_t)v;
}

EXPORT void
pb_write_bytes(ibuf_t *b, const uint8_t *src, size_t n)
{
	pb_ibuf_reserve(b, n);
	memcpy(b->data + b->len, src, n);
	b->len += n;
}

/* Combined "string field": tag + length + payload. Three primitives
 * fused into one to lower FFI call count for the most common field
 * shape; honesty note in README. */
EXPORT void
pb_write_string_field(ibuf_t *b, uint32_t tag, const uint8_t *src,
                      size_t n)
{
	pb_write_varint(b, tag);
	pb_write_varint(b, n);
	pb_write_bytes(b, src, n);
}

/* Returns a pointer past the varint, or NULL on truncation. */
EXPORT const uint8_t *
pb_read_varint(const uint8_t *p, const uint8_t *end, uint64_t *out)
{
	uint64_t v = 0;
	int shift = 0;
	while (p < end) {
		uint8_t c = *p++;
		v |= (uint64_t)(c & 0x7f) << shift;
		if (!(c & 0x80)) {
			*out = v;
			return p;
		}
		shift += 7;
		if (shift >= 64)
			return NULL;
	}
	return NULL;
}