-
Notifications
You must be signed in to change notification settings - Fork 5
/
buffer.c
200 lines (179 loc) · 4.87 KB
/
buffer.c
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
enum {
BUFFER_TYPE_INT=1,
BUFFER_TYPE_CHAR=2,
BUFFER_TYPE_FLOAT=3,
BUFFER_TYPE_DOUBLE=4,
} ;
// -----------------------------------------------------------------------------
// buffer
// -----------------------------------------------------------------------------
static void buf_push_buffer(lua_State *L, const void *p, size_t size)
{
void *newbuf = lua_newuserdata(L, size);
if (newbuf == NULL) {
luaL_error(L, "buffer: not enough memory to allocate buffer");
}
if (p != NULL) {
memcpy(newbuf, p, size);
}
else {
memset(newbuf, 0, size);
}
luaL_setmetatable(L, "buffer");
}
static int buffer_new_buffer(lua_State *L)
{
int type = lua_type(L, 1);
size_t N;
const void *buf = NULL;
switch (type) {
case LUA_TNUMBER:
N = luaL_checkunsigned(L, 1);
buf = NULL;
break;
case LUA_TSTRING:
N = lua_rawlen(L, 1);
buf = lua_tostring(L, 1);
break;
default:
N = 0;
luaL_error(L, "buffer: argument must be either number or string");
}
buf_push_buffer(L, buf, N);
return 1;
}
static int buffer_sizeof(lua_State *L)
{
unsigned int T = luaL_checkunsigned(L, 1);
size_t s = 0;
switch (T) {
case BUFFER_TYPE_CHAR: s = sizeof(char); break;
case BUFFER_TYPE_INT: s = sizeof(int); break;
case BUFFER_TYPE_FLOAT: s = sizeof(float); break;
case BUFFER_TYPE_DOUBLE: s = sizeof(double); break;
default:
luaL_error(L, "buffer: unknown data type specification");
}
lua_pushnumber(L, s);
return 1;
}
static int buffer_get_typed(lua_State *L)
{
const char *buf = luaL_checkudata(L, 1, "buffer");
unsigned int T = luaL_checkunsigned(L, 2); // type
unsigned int n = luaL_checkunsigned(L, 3); // index
unsigned int N = lua_rawlen(L, 1); // buffer size
size_t offset;
#define CASE(t) \
do { \
offset = n * sizeof(t); \
if (offset >= N) luaL_error(L, "buffer: index out of range"); \
lua_pushnumber(L, *((t*)(buf + offset))); \
} while(0) \
switch (T) {
case BUFFER_TYPE_CHAR: CASE(char); break;
case BUFFER_TYPE_INT: CASE(int); break;
case BUFFER_TYPE_FLOAT: CASE(float); break;
case BUFFER_TYPE_DOUBLE: CASE(double); break;
default:
luaL_error(L, "buffer: unknown data type specification");
}
#undef CASE
return 1;
}
static int buffer_set_typed(lua_State *L)
{
const char *buf = luaL_checkudata(L, 1, "buffer");
unsigned int T = luaL_checkunsigned(L, 2); // type
unsigned int n = luaL_checkunsigned(L, 3); // index
double v = luaL_checknumber(L, 4); // value
unsigned int N = lua_rawlen(L, 1); // buffer size
size_t offset;
#define CASE(t) \
do { \
offset = n * sizeof(t); \
if (offset >= N) luaL_error(L, "buffer: index out of range"); \
*((t*)(buf + offset)) = v; \
} while(0) \
switch (T) {
case BUFFER_TYPE_CHAR: CASE(char); break;
case BUFFER_TYPE_INT: CASE(int); break;
case BUFFER_TYPE_FLOAT: CASE(float); break;
case BUFFER_TYPE_DOUBLE: CASE(double); break;
default:
luaL_error(L, "buffer: unknown data type specification");
}
#undef CASE
return 0;
}
static int buffer__index(lua_State *L)
{
const char *buf = luaL_checkudata(L, 1, "buffer");
unsigned int n = luaL_checkunsigned(L, 2);
unsigned int N = lua_rawlen(L, 1);
if (n < N) {
lua_pushnumber(L, buf[n]);
}
else {
lua_pushnil(L);
}
return 1;
}
static int buffer__newindex(lua_State *L)
{
char *buf = luaL_checkudata(L, 1, "buffer"); // buffer
unsigned int n = luaL_checkunsigned(L, 2); // index
char val = luaL_checkinteger(L, 3); // value
unsigned int N = lua_rawlen(L, 1); // max index
if (n < N) {
buf[n] = val;
}
else {
luaL_error(L, "buffer: index %d out of range on buffer of length %d", n, N);
}
return 0;
}
static int buffer__len(lua_State *L)
{
luaL_checkudata(L, 1, "buffer");
lua_pushnumber(L, lua_rawlen(L, 1));
return 1;
}
static int buffer__tostring(lua_State *L)
{
char *buf = luaL_checkudata(L, 1, "buffer");
lua_pushlstring(L, buf, lua_rawlen(L, 1));
return 1;
}
int luaopen_buffer(lua_State *L)
{
luaL_Reg buffer_types[] = {
{"new_buffer", buffer_new_buffer},
{"sizeof", buffer_sizeof},
{"get_typed", buffer_get_typed},
{"set_typed", buffer_set_typed},
{NULL, NULL}};
luaL_Reg buffer_meta[] = {
{"__index", buffer__index},
{"__newindex", buffer__newindex},
{"__len", buffer__len},
{"__tostring", buffer__tostring},
{NULL, NULL}};
luaL_newmetatable(L, "buffer");
luaL_setfuncs(L, buffer_meta, 0);
lua_pop(L, 1);
lua_newtable(L);
luaL_setfuncs(L, buffer_types, 0);
#define REG_NUMBER(s,t) lua_pushnumber(L, s); lua_setfield(L, -2, t);
REG_NUMBER(BUFFER_TYPE_CHAR, "char");
REG_NUMBER(BUFFER_TYPE_INT, "int");
REG_NUMBER(BUFFER_TYPE_FLOAT, "float");
REG_NUMBER(BUFFER_TYPE_DOUBLE, "double");
#undef REG_NUMBER
return 1;
}