Skip to content

Commit a8d0ff9

Browse files
committed
support for passing carray objects
1 parent ee78db5 commit a8d0ff9

File tree

11 files changed

+761
-106
lines changed

11 files changed

+761
-106
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
- name: setup
2525
run: |
2626
luarocks install .github/workflows/lua-llthreads2-0.1.6-1.rockspec
27+
luarocks --server=https://luarocks.org/dev install carray
2728
luarocks --server=https://luarocks.org/dev install mtmsg
2829
luarocks make rockspecs/mtstates-scm-0.rockspec
2930
@@ -36,6 +37,7 @@ jobs:
3637
lua test02.lua
3738
lua test03.lua
3839
lua test04.lua
40+
lua test05.lua
3941
cd ../examples
4042
lua example01.lua
4143
lua example02.lua

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This package is also available via LuaRocks, see https://luarocks.org/modules/os
2222
[Lua]: https://www.lua.org
2323
[Lanes]: https://luarocks.org/modules/benoitgermain/lanes
2424
[lua-llthreads2]: https://luarocks.org/modules/moteus/lua-llthreads2
25+
[carray]: https://github.com/osch/lua-carray
2526

2627
See below for full [reference documentation](#documentation).
2728

@@ -185,7 +186,8 @@ assert(thread:join())
185186
new created state.
186187
* *...* - additional parameters, are transfered to the new state and
187188
are given as arguments to the setup function. Arguments can be
188-
simple data types (string, number, boolean, nil, light user data).
189+
simple data types (string, number, boolean, nil, light user data)
190+
or [carray] objects.
189191

190192
This function returns a state referencing lua object with *state:isowner() == true*.
191193

@@ -295,15 +297,15 @@ assert(thread:join())
295297

296298
* *...* - All argument parameters are transfered to the state and given to the state
297299
callback function. Arguments can be simple data types (string, number,
298-
boolean, nil, light user data).
300+
boolean, nil, light user data) or [carray] objects.
299301

300302
If the state callback function is processed in a concurrently running thread the
301303
*state:call()* method waits for the other call to complete before the state callback
302304
function is invoked. See next method *state:tcall()* for calling a state with
303305
timeout parameter.
304306

305307
Returns the results of the state callback function. Results can be simple data types
306-
(string, number, boolean, nil, light user data).
308+
(string, number, boolean, nil, light user data) or [carray] objects.
307309

308310
Possible errors: *mtstates.error.interrupted*,
309311
*mtstates.error.invoking_state*,
@@ -321,11 +323,11 @@ assert(thread:join())
321323

322324
* *...* - additional argument parameters are transfered to the state and given to the state
323325
callback function. Arguments can be simple data types (string, number,
324-
boolean, nil, light user data).
326+
boolean, nil, light user data) or [carray] objects.
325327

326328
If the state could be accessed within the timeout *state:tcall()* returns the boolean
327329
value *true* and all results from the state callback function. Results can be simple
328-
data types (string, number, boolean, nil, light user data).
330+
data types (string, number, boolean, nil, light user data) or [carray] objects.
329331

330332
Returns *false* if the state could not be accessed during the timeout.
331333

appveyor.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ before_build:
4747
build_script:
4848
- echo "Making..."
4949
- luarocks install lua-llthreads2
50+
- luarocks --server=https://luarocks.org/dev install carray
5051
- luarocks --server=https://luarocks.org/dev install mtmsg
5152
- luarocks make rockspecs/mtstates-scm-0.rockspec
5253

@@ -60,6 +61,7 @@ test_script:
6061
- lua test02.lua
6162
- lua test03.lua
6263
- lua test04.lua
64+
- lua test05.lua
6365
- cd %APPVEYOR_BUILD_FOLDER%\examples
6466
- lua example01.lua
6567
- lua example02.lua

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ default: mtstates
33

44
BUILD_DATE := $(shell date "+%Y-%m-%dT%H:%M:%S")
55

6-
LNX_GCC_RUN := gcc -shared -fPIC -O2
6+
LNX_GCC_RUN := gcc -shared -fPIC -O2 -Werror=return-type
77
WIN_GCC_RUN := gcc -shared -fPIC -O2
88
MAC_GCC_RUN := MACOSX_DEPLOYMENT_TARGET=10.8 gcc -O2 -bundle -undefined dynamic_lookup -all_load
99

src/carray_capi.h

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
#ifndef CARRAY_CAPI_H
2+
#define CARRAY_CAPI_H
3+
4+
#ifndef CARRAY_CAPI_HAVE_LONG_LONG
5+
# include <limits.h>
6+
# if defined(LLONG_MAX)
7+
# define CARRAY_CAPI_HAVE_LONG_LONG 1
8+
# else
9+
# define CARRAY_CAPI_HAVE_LONG_LONG 0
10+
# endif
11+
#endif
12+
13+
#define CARRAY_CAPI_ID_STRING "_capi_carray"
14+
#define CARRAY_CAPI_VERSION_MAJOR -1
15+
#define CARRAY_CAPI_VERSION_MINOR 0
16+
#define CARRAY_CAPI_VERSION_PATCH 1
17+
18+
typedef struct carray_capi carray_capi;
19+
typedef struct carray_info carray_info;
20+
typedef struct carray carray;
21+
22+
typedef enum carray_type carray_type;
23+
typedef enum carray_attr carray_attr;
24+
25+
#ifndef CARRAY_CAPI_IMPLEMENT_SET_CAPI
26+
# define CARRAY_CAPI_IMPLEMENT_SET_CAPI 0
27+
#endif
28+
29+
#ifndef CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI
30+
# define CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI 0
31+
#endif
32+
33+
#ifndef CARRAY_CAPI_IMPLEMENT_GET_CAPI
34+
# define CARRAY_CAPI_IMPLEMENT_GET_CAPI 0
35+
#endif
36+
37+
enum carray_type
38+
{
39+
CARRAY_UCHAR = 1,
40+
CARRAY_SCHAR = 2,
41+
42+
CARRAY_SHORT = 3,
43+
CARRAY_USHORT = 4,
44+
45+
CARRAY_INT = 5,
46+
CARRAY_UINT = 6,
47+
48+
CARRAY_LONG = 7,
49+
CARRAY_ULONG = 8,
50+
51+
CARRAY_FLOAT = 9,
52+
CARRAY_DOUBLE = 10,
53+
54+
#if CARRAY_CAPI_HAVE_LONG_LONG
55+
CARRAY_LLONG = 11,
56+
CARRAY_ULLONG = 12,
57+
#endif
58+
};
59+
60+
enum carray_attr
61+
{
62+
CARRAY_DEFAULT = 0,
63+
CARRAY_READONLY = 1
64+
};
65+
66+
struct carray_info
67+
{
68+
carray_type type;
69+
carray_attr attr;
70+
size_t elementSize;
71+
size_t elementCount;
72+
};
73+
74+
/**
75+
* Carray C API.
76+
*/
77+
struct carray_capi
78+
{
79+
int version_major;
80+
int version_minor;
81+
int version_patch;
82+
83+
/**
84+
* May point to another (incompatible) version of this API implementation.
85+
* NULL if no such implementation exists.
86+
*
87+
* The usage of next_capi makes it possible to implement two or more
88+
* incompatible versions of the C API.
89+
*
90+
* An API is compatible to another API if both have the same major
91+
* version number and if the minor version number of the first API is
92+
* greater or equal than the second one's.
93+
*/
94+
void* next_capi;
95+
96+
/**
97+
* Creates new carray object which manages the underlying data.
98+
*
99+
* elementCount - number of elements
100+
* data - if not NULL, contains after the call the pointer
101+
* to the uninitialized array elements. the caller
102+
* is responsible for initializing the elements.
103+
* If NULL, the elements are initialized with zeros.
104+
*
105+
* Returns NULL pointer on parameter error.
106+
* This function may also raise a Lua error.
107+
*/
108+
carray* (*newCarray)(lua_State* L, carray_type t, carray_attr attr, size_t elementCount, void** data);
109+
110+
/**
111+
* Creates new carray object with a reference to underlying data
112+
* managed by the caller.
113+
*
114+
* elementCount - number of elements
115+
* dataRef - pointer to the element content. The caller guerantees that the content
116+
* memory remains valid until the release callback is called.
117+
* releaseCallback - is called by the carray object if the reference to the underlying
118+
* data is not any longer needed. This callback may also be NULL
119+
* for the case of static data.
120+
*
121+
* Returns NULL pointer on parameter error.
122+
* This function may also raise a Lua error.
123+
*/
124+
carray* (*newCarrayRef)(lua_State* L, carray_type t, carray_attr attr, void* dataRef, size_t elementCount,
125+
void (*releaseCallback)(void* dataRef, size_t elementCount));
126+
127+
/**
128+
* Returns a valid pointer if the Lua object at the given stack
129+
* index is a valid readable carray, otherwise returns NULL.
130+
*
131+
* info - contains information about the carray after the call
132+
* May be NULL.
133+
*
134+
* The returned carray object is be valid as long as the Lua
135+
* object at the given stack index remains valid.
136+
* To keep the carray object beyond this call, the function
137+
* retainConstCarray() should be called (see below).
138+
*/
139+
const carray* (*toReadableCarray)(lua_State* L, int index, carray_info* info);
140+
141+
/**
142+
* Returns a valid pointer if the Lua object at the given stack
143+
* index is a valid writable carray, otherwise returns NULL.
144+
*
145+
* info - contains information about the carray after the call
146+
* May be NULL.
147+
*
148+
* The returned carray object is valid as long as the Lua
149+
* object at the given stack index remains valid.
150+
* To keep the carray object beyond this call, the function
151+
* retainCarray() should be called (see below).
152+
*/
153+
carray* (*toWritableCarray)(lua_State* L, int index, carray_info* info);
154+
155+
/**
156+
* Increase the reference counter of the carray object.
157+
*
158+
* This function must be called after the function toCarray()
159+
* as long as the Lua object on the given stack index is
160+
* valid (see above).
161+
*/
162+
void (*retainCarray)(const carray* a);
163+
164+
/**
165+
* Decrease the reference counter of the carray object and
166+
* destructs the carray object if no reference is left.
167+
*/
168+
void (*releaseCarray)(const carray* a);
169+
170+
/**
171+
* Get pointer to elements.
172+
* offset - index of the first element, 0 <= offset < elementCount
173+
* count - number of elements, 0 <= offset + count <= elementCount
174+
* Returns the pointer to the element in the array at the given offset.
175+
* The caller may only read or write at most count elements at this pointer,
176+
* otherwise behaviour may be undefined.
177+
*/
178+
void* (*getWritableElementPtr)(carray* a, size_t offset, size_t count);
179+
180+
/**
181+
* Get pointer to elements.
182+
* offset - index of the first element, 0 <= offset < elementCount
183+
* count - number of elements, 0 <= offset + count <= elementCount
184+
* Returns the pointer to the element in the array at the given offset.
185+
* The caller may only read at most count elements at this pointer,
186+
* otherwise behaviour may be undefined.
187+
*/
188+
const void* (*getReadableElementPtr)(const carray* a, size_t offset, size_t count);
189+
};
190+
191+
#if CARRAY_CAPI_IMPLEMENT_SET_CAPI
192+
/**
193+
* Sets the Carray C API into the metatable at the given index.
194+
*
195+
* index: index of the table that is be used as metatable for objects
196+
* that are associated to the given capi.
197+
*/
198+
static int carray_set_capi(lua_State* L, int index, const carray_capi* capi)
199+
{
200+
lua_pushlstring(L, CARRAY_CAPI_ID_STRING, strlen(CARRAY_CAPI_ID_STRING)); /* -> key */
201+
void** udata = lua_newuserdata(L, sizeof(void*) + strlen(CARRAY_CAPI_ID_STRING) + 1); /* -> key, value */
202+
*udata = (void*)capi;
203+
strcpy((char*)(udata + 1), CARRAY_CAPI_ID_STRING); /* -> key, value */
204+
lua_rawset(L, (index < 0) ? (index - 2) : index); /* -> */
205+
return 0;
206+
}
207+
#endif /* CARRAY_CAPI_IMPLEMENT_SET_CAPI */
208+
209+
#if CARRAY_CAPI_IMPLEMENT_GET_CAPI || CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI
210+
/**
211+
* Gives the associated Carray C API for the object at the given stack index.
212+
* Returns NULL, if the object at the given stack index does not have an
213+
* associated Carray C API or only has a Carray C API with incompatible version
214+
* number. If errorReason is not NULL it receives the error reason in this case:
215+
* 1 for incompatible version nummber and 2 for no associated C API at all.
216+
*/
217+
static const carray_capi* carray_get_capi(lua_State* L, int index, int* errorReason)
218+
{
219+
if (luaL_getmetafield(L, index, CARRAY_CAPI_ID_STRING) != LUA_TNIL) /* -> _capi */
220+
{
221+
void** udata = lua_touserdata(L, -1); /* -> _capi */
222+
223+
if ( udata
224+
&& (lua_rawlen(L, -1) >= sizeof(void*) + strlen(CARRAY_CAPI_ID_STRING) + 1)
225+
&& (memcmp((char*)(udata + 1), CARRAY_CAPI_ID_STRING,
226+
strlen(CARRAY_CAPI_ID_STRING) + 1) == 0))
227+
{
228+
const carray_capi* capi = *udata; /* -> _capi */
229+
while (capi) {
230+
if ( capi->version_major == CARRAY_CAPI_VERSION_MAJOR
231+
&& capi->version_minor >= CARRAY_CAPI_VERSION_MINOR)
232+
{ /* -> _capi */
233+
lua_pop(L, 1); /* -> */
234+
return capi;
235+
}
236+
capi = capi->next_capi;
237+
}
238+
if (errorReason) {
239+
*errorReason = 1;
240+
}
241+
} else { /* -> _capi */
242+
if (errorReason) {
243+
*errorReason = 2;
244+
}
245+
}
246+
lua_pop(L, 1); /* -> */
247+
} else { /* -> */
248+
if (errorReason) {
249+
*errorReason = 2;
250+
}
251+
}
252+
return NULL;
253+
}
254+
#endif /* CARRAY_CAPI_IMPLEMENT_GET_CAPI || CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI */
255+
256+
#if CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI
257+
258+
static const carray_capi* carray_require_capi(lua_State* L)
259+
{
260+
if (luaL_loadstring(L, "return require('carray')") != 0) { /* -> chunk */
261+
lua_error(L);
262+
}
263+
lua_call(L, 0, 1); /* -> carray */
264+
int errorReason;
265+
const carray_capi* capi = carray_get_capi(L, -1, &errorReason);
266+
if (!capi) {
267+
if (errorReason == 1) {
268+
luaL_error(L, "carray capi version mismatch");
269+
} else {
270+
luaL_error(L, "carray capi not found");
271+
}
272+
}
273+
lua_pop(L, 1);
274+
return capi;
275+
}
276+
277+
#endif /* CARRAY_CAPI_IMPLEMENT_REQUIRE_CAPI */
278+
279+
#endif /* CARRAY_CAPI_H */

0 commit comments

Comments
 (0)