1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-26 08:20:27 +00:00

implement typed array marshal/unmarshal and

generic marshaling capabilities to abstract types.
This commit is contained in:
J.-F. Cap 2019-02-23 16:58:47 +01:00
parent 7cb1c7cef2
commit 0cc6c6ff33
4 changed files with 182 additions and 52 deletions

View File

@ -319,7 +319,7 @@ static int marshal_one_abstract(MarshalState *st, Janet x, int flags) {
if (! info) return 1 ; /* unregistered type skip marshalling*/
if (info->marshal) {
MARK_SEEN();
JanetMarshalContext context={st,NULL,flags};
JanetMarshalContext context={st,NULL,flags,NULL};
pushbyte(st, LB_ABSTRACT);
pushint(st,info->tag);
info->marshal(janet_unwrap_abstract(x),&context);
@ -576,7 +576,8 @@ enum {
UMR_EXPECTED_STRING,
UMR_INVALID_REFERENCE,
UMR_INVALID_BYTECODE,
UMR_INVALID_FIBER
UMR_INVALID_FIBER,
UMR_INVALID_ABSTRACT
} UnmarshalResult;
const char *umr_strings[] = {
@ -590,7 +591,8 @@ const char *umr_strings[] = {
"expected string",
"invalid reference",
"invalid bytecode",
"invalid fiber"
"invalid fiber",
"invalid abstract",
};
/* Helper to read a 32 bit integer from an unmarshal state */
@ -954,6 +956,59 @@ error:
return NULL;
}
void janet_unmarshal_int(JanetMarshalContext *ctx,int32_t* i) {
UnmarshalState *st =(UnmarshalState *)(ctx->u_state);
*i=readint(st,&(ctx->data));
};
void janet_unmarshal_uint(JanetMarshalContext *ctx,uint32_t* i) {
UnmarshalState *st =(UnmarshalState *)(ctx->u_state);
*i=(uint32_t)readint(st,&(ctx->data));
};
void janet_unmarshal_size(JanetMarshalContext *ctx,size_t* i) {
UnmarshalState *st =(UnmarshalState *)(ctx->u_state);
*i=(size_t)readint(st,&(ctx->data));
};
void janet_unmarshal_byte(JanetMarshalContext *ctx,uint8_t* b) {
*b=*(ctx->data++);
};
void janet_unmarshal_bytes(JanetMarshalContext *ctx,uint8_t *dest, int32_t len) {
memcpy(dest,ctx->data,len);
ctx->data+=len;
}
void janet_unmarshal_janet(JanetMarshalContext *ctx,Janet *out) {
UnmarshalState *st =(UnmarshalState *)(ctx->u_state);
ctx->data=unmarshal_one(st,ctx->data,out,ctx->flags);
}
static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t *data, Janet *out, int flags) {
uint32_t tag=readint(st,&data);
const JanetAbstractTypeInfo *info = janet_get_abstract_type_info(tag);
if (info==NULL) goto error;
if (info->unmarshal) {
void *p = janet_abstract(info->at,info->size);
JanetMarshalContext context={NULL,st,flags,data};
info->unmarshal(p,&context);
*out=janet_wrap_abstract(p);
return data;
}
return 0;
error:
longjmp(st->err, UMR_INVALID_ABSTRACT);
return NULL;
}
static const uint8_t *unmarshal_one(
UnmarshalState *st,
const uint8_t *data,
@ -1067,6 +1122,10 @@ static const uint8_t *unmarshal_one(
}
return data;
}
case LB_ABSTRACT: {
data++;
return unmarshal_one_abstract(st,data,out,flags);
}
case LB_REFERENCE:
case LB_ARRAY:
case LB_TUPLE:

View File

@ -80,8 +80,7 @@ static size_t ta_type_sizes[] = {
sizeof(ta_float64_t),
};
#define TA_COUNT_TYPES (TA_TYPE_float64 + 1)
#define TA_ATOM_MAXSIZE 8;
#define TA_ATOM_MAXSIZE 8
#define TA_FLAG_BIG_ENDIAN 1
static TA_Type get_ta_type_by_name(const uint8_t *name) {
@ -99,7 +98,7 @@ static TA_Type get_ta_type_by_name(const uint8_t *name) {
typedef struct {
uint8_t *data;
size_t size;
int32_t flags;
uint32_t flags;
} TA_Buffer;
static TA_Buffer *ta_buffer_init(TA_Buffer *buf, size_t size) {
@ -127,12 +126,25 @@ static void ta_buffer_marshal(void *p, JanetMarshalContext *ctx) {
janet_marshal_bytes(ctx,buf->data,buf->size);
}
static void ta_buffer_unmarshal(void *p, JanetMarshalContext *ctx) {
TA_Buffer *buf = (TA_Buffer *)p;
uint32_t size;
janet_unmarshal_uint(ctx,&size);
ta_buffer_init(buf,size); // warning if indianess <> platform ??
janet_unmarshal_uint(ctx,&(buf->flags));
janet_unmarshal_bytes(ctx,buf->data,buf->size);
}
static const JanetAbstractType ta_buffer_type={"ta/buffer", ta_buffer_gc, NULL, NULL, NULL};
static const JanetAbstractTypeInfo ta_buffer_typeinfo={
&ta_buffer_type,
sizeof(TA_Buffer),
1000,
0,
ta_buffer_marshal,
ta_buffer_unmarshal,
};
@ -154,13 +166,30 @@ static int ta_mark(void *p, size_t s) {
static void ta_view_marshal(void *p, JanetMarshalContext *ctx) {
TA_View *view = (TA_View *)p;
size_t offset = (view->buffer->data - (uint8_t *)(view->data));
janet_marshal_int(ctx,view->size);
janet_marshal_int(ctx,view->stride);
janet_marshal_int(ctx,view->type);
janet_marshal_int(ctx,offset);
janet_marshal_janet(ctx,janet_wrap_abstract(view->buffer));
}
static void ta_view_unmarshal(void *p, JanetMarshalContext *ctx) {
TA_View *view = (TA_View *)p;
size_t offset;
Janet buffer;
janet_unmarshal_size(ctx,&(view->size));
janet_unmarshal_size(ctx,&(view->stride));
janet_unmarshal_uint(ctx,&(view->type));
janet_unmarshal_size(ctx,&offset);
janet_unmarshal_janet(ctx,&buffer);
view->buffer=(TA_Buffer *)janet_unwrap_abstract(buffer);
view->data=view->buffer->data+offset;
}
#define DEFINE_VIEW_TYPE(thetype) \
@ -250,11 +279,11 @@ BUILD_TYPE(float64)
#undef DEFINE_VIEW_INITIALIZER
#undef DEFINE_VIEW_ABSTRACT_TYPE
#define VIEW_ABSTRACT_INFO_INIT(type,tag) {&ta_view_##type##_t,tag,ta_view_marshal}
#define VIEW_ABSTRACT_INFO_INIT(type,salt) {&ta_view_##type##_t,sizeof(TA_View),salt,0,ta_view_marshal,ta_view_unmarshal}
static const JanetAbstractTypeInfo ta_array_types[] = {
VIEW_ABSTRACT_INFO_INIT(uint8,1001),
VIEW_ABSTRACT_INFO_INT(int8,1002),
VIEW_ABSTRACT_INFO_INIT(int8,1002),
VIEW_ABSTRACT_INFO_INIT(uint16,1003),
VIEW_ABSTRACT_INFO_INIT(int16,1004),
VIEW_ABSTRACT_INFO_INIT(uint32,1005),
@ -371,28 +400,41 @@ static Janet cfun_abstract_properties(int32_t argc, Janet *argv) {
if (info==NULL) {
return janet_wrap_nil();
}
JanetKV *props = janet_struct_begin(2);
JanetKV *props = janet_struct_begin(5);
janet_struct_put(props, janet_ckeywordv("tag"), janet_wrap_number(info->tag));
janet_struct_put(props, janet_ckeywordv("salt"), janet_wrap_number(info->salt));
janet_struct_put(props, janet_ckeywordv("name"), janet_ckeywordv(info->at->name));
janet_struct_put(props, janet_ckeywordv("size"), janet_wrap_number(info->size));
janet_struct_put(props, janet_ckeywordv("marshal"), janet_wrap_boolean((info->marshal !=NULL) && (info->unmarshal!=NULL)));
return janet_wrap_struct(janet_struct_end(props));
}
/*
static Janet cfun_typed_array_copy_bytes(int32_t argc, Janet *argv) {
janet_fixarity(argc, 4);
janet_arity(argc, 4, 5);
if (is_ta_type(argv[0]) && is_ta_type(argv[2])) {
TA_View *src = (TA_View *)janet_unwrap_abstract(argv[0]);
size_t index_src=(size_t)janet_getinteger(argv, 1);
TA_View *dst = (TA_View *)janet_unwrap_abstract(argv[2]);
size_t index_dst=(size_t)janet_getinteger(argv, 3);
size_t count=(argc == 5)? (size_t)janet_getinteger(argv, 4) : 1;
size_t src_atom_size=ta_type_sizes[src->type];
size_t dst_atom_size=ta_type_sizes[dst->type];
size_t pos_src=((uint8_t *)(src->data) - src->buffer->data)+(index_src*src->stride*src_atom_size);
size_t pos_dst=((uint8_t *)(dst->data) - dst->buffer->data)+(index_dst*dst->stride*dst_atom_size);
if (pos_dst+src_atom_size <= dst->buffer->size)
memmove(dst->buffer->data+pos_dst,src->buffer->data+pos_src,src_atom_size);
size_t step_src=src->stride*src_atom_size;
size_t step_dst=dst->stride*dst_atom_size;
size_t pos_src=((uint8_t *)(src->data) - src->buffer->data)+(index_src*step_src);
size_t pos_dst=((uint8_t *)(dst->data) - dst->buffer->data)+(index_dst*step_dst);
uint8_t * ps=src->buffer->data+pos_src,* pd=dst->buffer->data+pos_dst;
if ((pos_dst+(count-1)*step_dst+src_atom_size <= dst->buffer->size) &&
(pos_src+(count-1)*step_src+src_atom_size <= src->buffer->size)) {
for (size_t i=0;i<count;i++) {
memmove(pd,ps,src_atom_size);
pd+=step_dst;
ps+=step_src;
}
}
else
janet_panic("typed array out of bound");
janet_panic("typed array copy out of bound");
} else {
janet_panic("expected typed array");
}
@ -400,32 +442,39 @@ static Janet cfun_typed_array_copy_bytes(int32_t argc, Janet *argv) {
}
static Janet cfun_typed_array_swap_bytes(int32_t argc, Janet *argv) {
janet_fixarity(argc, 4);
janet_arity(argc, 4, 5);
if (is_ta_type(argv[0]) && is_ta_type(argv[2])) {
TA_View *src = (TA_View *)janet_unwrap_abstract(argv[0]);
size_t index_src=(size_t)janet_getinteger(argv, 1);
TA_View *dst = (TA_View *)janet_unwrap_abstract(argv[2]);
size_t index_dst=(size_t)janet_getinteger(argv, 3);
size_t count=(argc == 5)? (size_t)janet_getinteger(argv, 4) : 1;
size_t src_atom_size=ta_type_sizes[src->type];
size_t dst_atom_size=ta_type_sizes[dst->type];
size_t pos_src=((uint8_t *)(src->data) - src->buffer->data)+(index_src*src->stride*src_atom_size);
size_t pos_dst=((uint8_t *)(dst->data) - dst->buffer->data)+(index_dst*dst->stride*dst_atom_size);
size_t step_src=src->stride*src_atom_size;
size_t step_dst=dst->stride*dst_atom_size;
size_t pos_src=((uint8_t *)(src->data) - src->buffer->data)+(index_src*step_src);
size_t pos_dst=((uint8_t *)(dst->data) - dst->buffer->data)+(index_dst*step_dst);
uint8_t * ps=src->buffer->data+pos_src,* pd=dst->buffer->data+pos_dst;
uint8_t temp[TA_ATOM_MAXSIZE];
if (pos_dst+src_atom_size <= dst->buffer->size) {
uint8_t * src_ptr=src->buffer->data+pos_src;
uint8_t * dst_ptr=dst->buffer->data+pos_dst;
memcpy(temp,src_ptr,src_atom_size);
memcpy(src_ptr,dst_ptr,src_atom_size);
memcpy(dst_ptr,temp,src_atom_size);
if ((pos_dst+(count-1)*step_dst+src_atom_size <= dst->buffer->size) &&
(pos_src+(count-1)*step_src+src_atom_size <= src->buffer->size)) {
for (size_t i=0;i<count;i++) {
memcpy(temp,ps,src_atom_size);
memcpy(ps,pd,src_atom_size);
memcpy(pd,temp,src_atom_size);
pd+=step_dst;
ps+=step_src;
}
}
else
janet_panic("typed array buffer out of bound");
janet_panic("typed array swap out of bound");
} else {
janet_panic("expected typed array");
}
return janet_wrap_nil();
}
*/
static const JanetReg ta_cfuns[] = {
@ -449,6 +498,22 @@ static const JanetReg ta_cfuns[] = {
JDOC("(tarray/properties array )\n\n"
"return typed array properties as a struct")
},
{
"tarray/copy-bytes", cfun_typed_array_copy_bytes,
JDOC("(tarray/copy-bytes src sindex dst dindex [count=1])\n\n"
"copy count elements of src array from index sindex \n"
"to dst array at position dindex \n"
"memory can overlap"
)
},
{
"tarray/swap-bytes", cfun_typed_array_swap_bytes,
JDOC("(tarray/swap-bytes src sindex dst dindex [count=1])\n\n"
"swap count elements between src array from index sindex \n"
"and dst array at position dindex \n"
"memory can overlap"
)
},
{
"abstract/properties", cfun_abstract_properties,
JDOC("(abstract/properties tag)\n\n"

View File

@ -284,31 +284,30 @@ void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns)
}
}
/* Abstract type introspection */
static const JanetAbstractType type_info = {"core/type_info", NULL, NULL, NULL, NULL};
/*
void janet_register_abstract_type(const JanetAbstractType *atype,uint32_t tag) {
JanetAbstractTypeInfo * abstract =(JanetAbstractTypeInfo *)janet_abstract(&type_info,sizeof(JanetAbstractTypeInfo));
abstract->type=*atype;
abstract->tag=tag;
if (!(janet_checktype(janet_table_get(janet_vm_registry,janet_wrap_number(tag)),JANET_NIL)) ||
!(janet_checktype(janet_table_get(janet_vm_registry,janet_ckeywordv(atype->name)),JANET_NIL))) {
janet_panic("Register abstract type fail, a type with same name or tag exist");
}
janet_table_put(janet_vm_registry,janet_wrap_number(tag), janet_wrap_abstract(abstract));
janet_table_put(janet_vm_registry,janet_ckeywordv(atype->name), janet_wrap_abstract(abstract));
static uint32_t janet_abstract_type_gentag(const char * name,uint32_t salt) {
/* something smarter should propably done here ? */
int32_t len = strlen(name);
const char *end = name + len;
uint32_t hash = 5381+salt;
while (name < end)
hash = (hash << 5) + hash + *name++;
return (int32_t) hash;
}
*/
void janet_register_abstract_type(const JanetAbstractTypeInfo * info) {
JanetAbstractTypeInfo * abstract =(JanetAbstractTypeInfo *)janet_abstract(&type_info,sizeof(JanetAbstractTypeInfo));
memcpy(abstract,info,sizeof(JanetAbstractTypeInfo));
if (!(janet_checktype(janet_table_get(janet_vm_registry,janet_wrap_number(info->tag)),JANET_NIL)) ||
!(janet_checktype(janet_table_get(janet_vm_registry,janet_ckeywordv(info->at->name)),JANET_NIL))) {
memcpy(abstract,info,sizeof(JanetAbstractTypeInfo));
abstract->tag=janet_abstract_type_gentag(info->at->name,info->salt);
if (!(janet_checktype(janet_table_get(janet_vm_registry,janet_wrap_number(abstract->tag)),JANET_NIL)) ||
!(janet_checktype(janet_table_get(janet_vm_registry,janet_ckeywordv(abstract->at->name)),JANET_NIL))) {
janet_panic("Register abstract type fail, a type with same name or tag exist");
}
janet_table_put(janet_vm_registry,janet_wrap_number(info->tag), janet_wrap_abstract(abstract));
janet_table_put(janet_vm_registry,janet_ckeywordv(info->at->name), janet_wrap_abstract(abstract));
janet_table_put(janet_vm_registry,janet_wrap_number(abstract->tag), janet_wrap_abstract(abstract));
janet_table_put(janet_vm_registry,janet_ckeywordv(abstract->at->name), janet_wrap_abstract(abstract));
}

View File

@ -1243,30 +1243,37 @@ JANET_API JanetRange janet_getslice(int32_t argc, const Janet *argv);
JANET_API int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which);
JANET_API int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which);
typedef struct {
void * m_state; /* void* to not expose MarshalState ?*/
void * u_state;
int flags;
const uint8_t * data;
} JanetMarshalContext;
void janet_marshal_int(JanetMarshalContext *ctx,int32_t value);
void janet_marshal_byte(JanetMarshalContext *ctx,uint8_t value);
void janet_marshal_bytes(JanetMarshalContext *ctx,const uint8_t *bytes, int32_t len);
void janet_marshal_janet(JanetMarshalContext *ctx,Janet x);
JANET_API void janet_marshal_int(JanetMarshalContext *ctx,int32_t value);
JANET_API void janet_marshal_byte(JanetMarshalContext *ctx,uint8_t value);
JANET_API void janet_marshal_bytes(JanetMarshalContext *ctx,const uint8_t *bytes, int32_t len);
JANET_API void janet_marshal_janet(JanetMarshalContext *ctx,Janet x);
JANET_API void janet_unmarshal_int(JanetMarshalContext *ctx,int32_t* i);
JANET_API void janet_unmarshal_uint(JanetMarshalContext *ctx,uint32_t* i);
JANET_API void janet_unmarshal_size(JanetMarshalContext *ctx,size_t * i);
JANET_API void janet_unmarshal_byte(JanetMarshalContext *ctx,uint8_t* b);
JANET_API void janet_unmarshal_bytes(JanetMarshalContext *ctx,uint8_t *dest, int32_t len);
JANET_API void janet_unmarshal_janet(JanetMarshalContext *ctx,Janet *out);
typedef struct {
const JanetAbstractType *at;
const uint32_t tag;
size_t size; /* abstract type size */
const uint32_t salt; /* salt */
uint32_t tag; /* unique tag computed by janet (hash of name and salt) */
void (* marshal)(void *p,JanetMarshalContext *ctx);
void (* unmarshal)(void *p,JanetMarshalContext *ctx);
} JanetAbstractTypeInfo;
JANET_API void janet_register_abstract_type(const JanetAbstractTypeInfo * info);
JANET_API JanetAbstractTypeInfo * janet_get_abstract_type_info(uint32_t tag);
/*JANET_API uint32_t janet_get_abstract_type_tag(const JanetAbstractType *atype);*/
JANET_API JanetAbstractTypeInfo * janet_get_abstract_type_info_byname(const char * name);