AN ADDRESS IS NOT AN INTEGER!
I remember this crap going from 16 bit to 32 bit systems [1] and frankly,
I'd rather not have to live through that again going to 64 bit [3][4].
An address in not an integer, but a handle can be.
For example, in posix , file handle is an integer , and file is an object ,too.
We don't need create more than 2^32 userdata in one lua vm, so we can create an array in lua global state ( G(L) ), and use an integer index to indicate the userdata object's address.
It would be like this:
union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
struct {
int handle;
int slice ;
} u; /* full userdata with an integer */
};
and add an array in global_State
typedef struct global_State {
int userdata_cap;
struct Udata *userdata_array;
....
};
The lua_touserdata could be:
LUA_API void *lua_touserdata (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
switch (ttnov(o)) {
case LUA_TUSERDATA: return G(L)->userdata_array[o->u.handle];
case LUA_TLIGHTUSERDATA: return pvalue(o);
default: return NULL;
}
}
Also, I don't think I'm following your API there. I have this structure:
typedef union sockaddr_all
{
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_un ssun;
} sockaddr_all__t;
which I'm using for a userdata. I have a custom __index method associated
with this that gives me the following "fields":
addr - text representation of IPv4/IPv6 address
daddr - other text representation of IPv4/IPv6 address [5]
addrbits - The raw binary bits that make up an IPv4/IPv6 address
port - port number
family - string, either 'ip', 'ip6' or 'unix'.
display - textual representation of address and port.
How would your system with with that?
[1] Want to know how false this is? I can name a mainstream system that
used C, that could have both 16 *AND* 32 bit pointers *IN THE SAME
PROGRAM* and where ints were 16 *BITS* long. [2]
You can use 1 for sa, 2 for sin, 3 for sin6 , and 4 for ssun. 0 means the sockaddr_all.
In lua, you can use
local sall = create_sockaddr(...) -- sa is an userdata that store sockaddr_all__t
local sin = sall.sin
print(sin.port)
How to implement these by new api lua_getuserslice and lua_setuserslice ?
#define SOCKADDR 0
#define SOCKADDR_SIN 1
#define SOCKADDR_SIN6 2
#define SOCKADDR_UN 3
int sa_root_index(lua_State *L) {
const char * f = luaL_checkstring(L, 2);
int slice = 0;
if (strcmp(f, "sin")== 0)
slice = 1;
else if (strcmp(f, "sin6") == 0)
slice = 2;
else if (strcmp(f, "un") == 0)
slice = 3;
else
return luaL_error(L, "never here");
lua_settop(L,1);
lua_setuserslice(L,1,slice);
return 1;
}
int sa_sin_index(lua_State *L) {
const char * f = luaL_checkstring(L, 2);
sockaddr_all_t *obj = lua_touserdata(L,1);
if (strcmp(f, "port") == 0)
lua_pushinteger(L, obj->sin.sin_port);
else {
// todo: supoort sin.sin_family ... etc
}
return 1;
}
int sockaddr_index(lua_State *L) {
// todo: do more type check
sockaddr_all_t *obj = lua_touserdata(L,1);
int slice = lua_getuserslice(L,1);
switch (slice) {
case SOCKADDR :
return sa_root_index(L);
case SOCKADDR_SIN:
return sa_sin_index(L);
case SOCKADDR_SIN6:
return sa_sin6_index(L);
case SOCKADDR_UN:
return sa_un_index(L);
}
return luaL_error(L, "never here");
}
I don't like 2G limit of LuaJIT, too. and I spent months to remove the limit , but failed.