add interface to base lib and improve handling of empty lists
This commit is contained in:
parent
93f695f77c
commit
21e7c29a96
5 changed files with 137 additions and 101 deletions
|
|
@ -13,6 +13,7 @@ UINT_T CAT(capn_get,SZ) (CAT(capn_list,SZ) l, int off) {
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
if (p.datasz < SZ/8)
|
if (p.datasz < SZ/8)
|
||||||
return 0;
|
return 0;
|
||||||
d = p.data + off * (p.datasz + p.ptrsz);
|
d = p.data + off * (p.datasz + p.ptrsz);
|
||||||
|
|
@ -40,6 +41,7 @@ int CAT(capn_getv,SZ) (CAT(capn_list,SZ) l, int off, UINT_T *to, int sz) {
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) {
|
if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) {
|
||||||
memcpy(to, p.data + off, sz * (SZ/8));
|
memcpy(to, p.data + off, sz * (SZ/8));
|
||||||
return sz;
|
return sz;
|
||||||
|
|
@ -78,6 +80,7 @@ int CAT(capn_set,SZ) (CAT(capn_list,SZ) l, int off, UINT_T v) {
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
if (p.datasz < SZ/8)
|
if (p.datasz < SZ/8)
|
||||||
return -1;
|
return -1;
|
||||||
d = p.data + off * (p.datasz + p.ptrsz);
|
d = p.data + off * (p.datasz + p.ptrsz);
|
||||||
|
|
@ -106,6 +109,7 @@ int CAT(capn_setv,SZ) (CAT(capn_list,SZ) l, int off, const UINT_T *from, int sz)
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) {
|
if (p.datasz == SZ/8 && !p.ptrsz && (SZ == 8 || CAPN_LITTLE)) {
|
||||||
memcpy(p.data + off, from, sz * (SZ/8));
|
memcpy(p.data + off, from, sz * (SZ/8));
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ static void setupStruct(struct capn *ctx) {
|
||||||
ASSERT_EQ(CAPN_PTR_LIST, root.type);
|
ASSERT_EQ(CAPN_PTR_LIST, root.type);
|
||||||
ASSERT_EQ(1, root.len);
|
ASSERT_EQ(1, root.len);
|
||||||
|
|
||||||
struct capn_ptr ptr = capn_new_struct(root.seg, 16, 5);
|
struct capn_ptr ptr = capn_new_struct(root.seg, 16, 6);
|
||||||
ASSERT_EQ(CAPN_STRUCT, ptr.type);
|
ASSERT_EQ(CAPN_STRUCT, ptr.type);
|
||||||
EXPECT_EQ(16, ptr.datasz);
|
EXPECT_EQ(16, ptr.datasz);
|
||||||
EXPECT_EQ(40, ptr.ptrsz);
|
EXPECT_EQ(48, ptr.ptrsz);
|
||||||
EXPECT_EQ(0, capn_setp(root, 0, ptr));
|
EXPECT_EQ(0, capn_setp(root, 0, ptr));
|
||||||
|
|
||||||
EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617)));
|
EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617)));
|
||||||
|
|
@ -105,16 +105,14 @@ static void setupStruct(struct capn *ctx) {
|
||||||
EXPECT_EQ(0, capn_setp(ptr, 1, list32.p));
|
EXPECT_EQ(0, capn_setp(ptr, 1, list32.p));
|
||||||
|
|
||||||
capn_ptr list = capn_new_list(ptr.seg, 4, 4, 1);
|
capn_ptr list = capn_new_list(ptr.seg, 4, 4, 1);
|
||||||
ASSERT_EQ(CAPN_LIST, list.type);
|
ASSERT_EQ(CAPN_COMPOSITE_LIST, list.type);
|
||||||
EXPECT_EQ(1, list.has_composite_tag);
|
|
||||||
EXPECT_EQ(4, list.len);
|
EXPECT_EQ(4, list.len);
|
||||||
EXPECT_EQ(8, list.datasz);
|
EXPECT_EQ(8, list.datasz);
|
||||||
EXPECT_EQ(8, list.ptrsz);
|
EXPECT_EQ(8, list.ptrsz);
|
||||||
EXPECT_EQ(0, capn_setp(ptr, 2, list));
|
EXPECT_EQ(0, capn_setp(ptr, 2, list));
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
capn_ptr element = capn_getp(list, i);
|
capn_ptr element = capn_getp(list, i);
|
||||||
ASSERT_EQ(CAPN_STRUCT, element.type);
|
ASSERT_EQ(CAPN_LIST_MEMBER, element.type);
|
||||||
EXPECT_EQ(1, element.is_list_member);
|
|
||||||
EXPECT_EQ(8, element.datasz);
|
EXPECT_EQ(8, element.datasz);
|
||||||
EXPECT_EQ(8, element.ptrsz);
|
EXPECT_EQ(8, element.ptrsz);
|
||||||
EXPECT_EQ(0, capn_write32(element, 0, 300+i));
|
EXPECT_EQ(0, capn_write32(element, 0, 300+i));
|
||||||
|
|
@ -149,13 +147,19 @@ static void setupStruct(struct capn *ctx) {
|
||||||
EXPECT_EQ(16, recurse.ptrsz);
|
EXPECT_EQ(16, recurse.ptrsz);
|
||||||
EXPECT_EQ(0, capn_setp(recurse, 0, recurse));
|
EXPECT_EQ(0, capn_setp(recurse, 0, recurse));
|
||||||
EXPECT_EQ(0, capn_setp(ptr, 4, recurse));
|
EXPECT_EQ(0, capn_setp(ptr, 4, recurse));
|
||||||
|
|
||||||
|
capn_ptr interface = capn_new_interface(ptr.seg, 0, 0);
|
||||||
|
EXPECT_EQ(CAPN_INTERFACE, interface.type);
|
||||||
|
EXPECT_EQ(0, interface.datasz);
|
||||||
|
EXPECT_EQ(0, interface.ptrsz);
|
||||||
|
EXPECT_EQ(0, capn_setp(ptr, 5, interface));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkStruct(struct capn *ctx) {
|
static void checkStruct(struct capn *ctx) {
|
||||||
capn_ptr ptr = capn_getp(capn_root(ctx), 0);
|
capn_ptr ptr = capn_getp(capn_root(ctx), 0);
|
||||||
EXPECT_EQ(CAPN_STRUCT, ptr.type);
|
EXPECT_EQ(CAPN_STRUCT, ptr.type);
|
||||||
EXPECT_EQ(16, ptr.datasz);
|
EXPECT_EQ(16, ptr.datasz);
|
||||||
EXPECT_EQ(40, ptr.ptrsz);
|
EXPECT_EQ(48, ptr.ptrsz);
|
||||||
EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0));
|
EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0));
|
||||||
EXPECT_EQ(UINT32_C(0x20212223), capn_read32(ptr, 8));
|
EXPECT_EQ(UINT32_C(0x20212223), capn_read32(ptr, 8));
|
||||||
EXPECT_EQ(0x3031, capn_read16(ptr, 12));
|
EXPECT_EQ(0x3031, capn_read16(ptr, 12));
|
||||||
|
|
@ -185,15 +189,14 @@ static void checkStruct(struct capn *ctx) {
|
||||||
EXPECT_EQ(202, capn_get16(list16, 2));
|
EXPECT_EQ(202, capn_get16(list16, 2));
|
||||||
|
|
||||||
capn_ptr list = capn_getp(ptr, 2);
|
capn_ptr list = capn_getp(ptr, 2);
|
||||||
EXPECT_EQ(CAPN_LIST, list.type);
|
EXPECT_EQ(CAPN_COMPOSITE_LIST, list.type);
|
||||||
EXPECT_EQ(4, list.len);
|
EXPECT_EQ(4, list.len);
|
||||||
EXPECT_EQ(8, list.datasz);
|
EXPECT_EQ(8, list.datasz);
|
||||||
EXPECT_EQ(8, list.ptrsz);
|
EXPECT_EQ(8, list.ptrsz);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
capn_ptr element = capn_getp(list, i);
|
capn_ptr element = capn_getp(list, i);
|
||||||
EXPECT_EQ(CAPN_STRUCT, element.type);
|
EXPECT_EQ(CAPN_LIST_MEMBER, element.type);
|
||||||
EXPECT_EQ(1, element.is_list_member);
|
|
||||||
EXPECT_EQ(8, element.datasz);
|
EXPECT_EQ(8, element.datasz);
|
||||||
EXPECT_EQ(8, element.ptrsz);
|
EXPECT_EQ(8, element.ptrsz);
|
||||||
EXPECT_EQ(300+i, capn_read32(element,0));
|
EXPECT_EQ(300+i, capn_read32(element,0));
|
||||||
|
|
@ -230,6 +233,11 @@ static void checkStruct(struct capn *ctx) {
|
||||||
EXPECT_EQ(recurse.seg, recurse_mbr.seg);
|
EXPECT_EQ(recurse.seg, recurse_mbr.seg);
|
||||||
EXPECT_EQ(recurse.data, recurse_mbr.data);
|
EXPECT_EQ(recurse.data, recurse_mbr.data);
|
||||||
EXPECT_EQ(CAPN_NULL, capn_getp(recurse, 1).type);
|
EXPECT_EQ(CAPN_NULL, capn_getp(recurse, 1).type);
|
||||||
|
|
||||||
|
capn_ptr interface = capn_getp(ptr, 5);
|
||||||
|
EXPECT_EQ(CAPN_INTERFACE, interface.type);
|
||||||
|
EXPECT_EQ(0, interface.datasz);
|
||||||
|
EXPECT_EQ(0, interface.ptrsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WireFormat, StructRoundTrip_OneSegment) {
|
TEST(WireFormat, StructRoundTrip_OneSegment) {
|
||||||
|
|
@ -238,7 +246,7 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
|
||||||
|
|
||||||
// word count:
|
// word count:
|
||||||
// 1 root reference
|
// 1 root reference
|
||||||
// 7 root struct
|
// 8 root struct
|
||||||
// 1 sub message
|
// 1 sub message
|
||||||
// 2 3-element int32 list
|
// 2 3-element int32 list
|
||||||
// 13 struct list
|
// 13 struct list
|
||||||
|
|
@ -252,9 +260,9 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
|
||||||
// 6 sub-lists (4x 1 word, 1x 2 words)
|
// 6 sub-lists (4x 1 word, 1x 2 words)
|
||||||
// 2 recurse
|
// 2 recurse
|
||||||
// -----
|
// -----
|
||||||
// 37
|
// 38
|
||||||
ASSERT_EQ(1, ctx.capn.segnum);
|
ASSERT_EQ(1, ctx.capn.segnum);
|
||||||
EXPECT_EQ(37*8, ctx.capn.seglist->len);
|
EXPECT_EQ(38*8, ctx.capn.seglist->len);
|
||||||
|
|
||||||
checkStruct(&ctx.capn);
|
checkStruct(&ctx.capn);
|
||||||
|
|
||||||
|
|
@ -296,7 +304,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
|
||||||
// Check that each segment has the expected size. Recall that the first word of each segment will
|
// Check that each segment has the expected size. Recall that the first word of each segment will
|
||||||
// actually be a reference to the first thing allocated within that segment.
|
// actually be a reference to the first thing allocated within that segment.
|
||||||
EXPECT_EQ( 8, segments[ 0]->len); // root ref
|
EXPECT_EQ( 8, segments[ 0]->len); // root ref
|
||||||
EXPECT_EQ(64, segments[ 1]->len); // root struct
|
EXPECT_EQ(72, segments[ 1]->len); // root struct
|
||||||
EXPECT_EQ(16, segments[ 2]->len); // sub-struct
|
EXPECT_EQ(16, segments[ 2]->len); // sub-struct
|
||||||
EXPECT_EQ(24, segments[ 3]->len); // 3-element int32 list
|
EXPECT_EQ(24, segments[ 3]->len); // 3-element int32 list
|
||||||
EXPECT_EQ(80, segments[ 4]->len); // struct list
|
EXPECT_EQ(80, segments[ 4]->len); // struct list
|
||||||
|
|
@ -337,7 +345,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation_NoTag) {
|
||||||
// Check that each segment has the expected size. Note that we have plenty
|
// Check that each segment has the expected size. Note that we have plenty
|
||||||
// of 16 byte double far ptrs.
|
// of 16 byte double far ptrs.
|
||||||
EXPECT_EQ( 8, segments[ 0]->len); // root ref
|
EXPECT_EQ( 8, segments[ 0]->len); // root ref
|
||||||
EXPECT_EQ(56, segments[ 1]->len); // root struct
|
EXPECT_EQ(64, segments[ 1]->len); // root struct
|
||||||
EXPECT_EQ(16, segments[ 2]->len); // root struct ptr
|
EXPECT_EQ(16, segments[ 2]->len); // root struct ptr
|
||||||
EXPECT_EQ( 8, segments[ 3]->len); // sub-struct
|
EXPECT_EQ( 8, segments[ 3]->len); // sub-struct
|
||||||
EXPECT_EQ(16, segments[ 4]->len); // sub-struct ptr
|
EXPECT_EQ(16, segments[ 4]->len); // sub-struct ptr
|
||||||
|
|
@ -411,12 +419,12 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
|
||||||
|
|
||||||
// Check that each segment has the expected size. Recall that each object will be prefixed by an
|
// Check that each segment has the expected size. Recall that each object will be prefixed by an
|
||||||
// extra word if its parent is in a different segment.
|
// extra word if its parent is in a different segment.
|
||||||
EXPECT_EQ(64, segments[0]->len); // root ref + struct (48)
|
EXPECT_EQ(64, segments[0]->len); // root ref (8), sub-struct (8+tag), 3-element list (16+tag), list substruct 1 (8+tag)
|
||||||
EXPECT_EQ(56, segments[1]->len); // sub (8+tag) + 3-element int32 list (16+tag) + struct list substructs 1 (8+tag)
|
EXPECT_EQ(72, segments[1]->len); // root struct (64+tag)
|
||||||
EXPECT_EQ(80, segments[2]->len); // struct list (72+tag)
|
EXPECT_EQ(80, segments[2]->len); // struct list (72+tag)
|
||||||
EXPECT_EQ(64, segments[3]->len); // struct list substructs 2+3+4 3*(8+tag) + list list sublist 3 (8+tag)
|
EXPECT_EQ(64, segments[3]->len); // list substruct 2,3,4 3*(8+tag), sublist 3 (8+tag)
|
||||||
EXPECT_EQ(64, segments[4]->len); // list list (40+tag) + sublist 1,2 2*(8)
|
EXPECT_EQ(64, segments[4]->len); // list list (40+tag), sublist 1,2 2*8
|
||||||
EXPECT_EQ(64, segments[5]->len); // list list sublist 4 (8+tag), 5 (16+tag) + recurse struct (16+tag)
|
EXPECT_EQ(64, segments[5]->len); // sublist 4 (8+tag), 5 (16+tag), recurse struct (16+tag)
|
||||||
|
|
||||||
checkStruct(&ctx.capn);
|
checkStruct(&ctx.capn);
|
||||||
|
|
||||||
|
|
|
||||||
171
capn.c
171
capn.c
|
|
@ -8,6 +8,7 @@
|
||||||
#define STRUCT_PTR 0
|
#define STRUCT_PTR 0
|
||||||
#define LIST_PTR 1
|
#define LIST_PTR 1
|
||||||
#define FAR_PTR 2
|
#define FAR_PTR 2
|
||||||
|
#define INTERFACE_PTR 3
|
||||||
#define DOUBLE_PTR 6
|
#define DOUBLE_PTR 6
|
||||||
|
|
||||||
#define VOID_LIST 0
|
#define VOID_LIST 0
|
||||||
|
|
@ -322,16 +323,26 @@ static capn_ptr read_ptr(struct capn_segment *s, char *d) {
|
||||||
|
|
||||||
d += (I32(U32(val)) >> 2) * 8 + 8;
|
d += (I32(U32(val)) >> 2) * 8 + 8;
|
||||||
|
|
||||||
if ((val&3) > LIST_PTR || d < s->data) {
|
if (d < s->data) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((val&3) == STRUCT_PTR) {
|
switch (val & 3) {
|
||||||
|
case STRUCT_PTR:
|
||||||
|
ret.type = val ? CAPN_STRUCT : CAPN_NULL;
|
||||||
|
goto struct_common;
|
||||||
|
|
||||||
|
case INTERFACE_PTR:
|
||||||
|
ret.type = CAPN_INTERFACE;
|
||||||
|
goto struct_common;
|
||||||
|
|
||||||
|
struct_common:
|
||||||
ret.datasz = U32(U16(val >> 32)) * 8;
|
ret.datasz = U32(U16(val >> 32)) * 8;
|
||||||
ret.ptrsz = U32(U16(val >> 48)) * 8;
|
ret.ptrsz = U32(U16(val >> 48)) * 8;
|
||||||
ret.type = (ret.datasz || ret.ptrsz) ? CAPN_STRUCT : CAPN_NULL;
|
|
||||||
e = d + ret.datasz + ret.ptrsz;
|
e = d + ret.datasz + ret.ptrsz;
|
||||||
} else {
|
break;
|
||||||
|
|
||||||
|
case LIST_PTR:
|
||||||
ret.type = CAPN_LIST;
|
ret.type = CAPN_LIST;
|
||||||
ret.len = val >> 35;
|
ret.len = val >> 35;
|
||||||
|
|
||||||
|
|
@ -377,13 +388,14 @@ static capn_ptr read_ptr(struct capn_segment *s, char *d) {
|
||||||
ret.datasz = U32(U16(val >> 32)) * 8;
|
ret.datasz = U32(U16(val >> 32)) * 8;
|
||||||
ret.ptrsz = U32(U16(val >> 48)) * 8;
|
ret.ptrsz = U32(U16(val >> 48)) * 8;
|
||||||
ret.len = U32(val) >> 2;
|
ret.len = U32(val) >> 2;
|
||||||
ret.has_composite_tag = 1;
|
ret.type = CAPN_COMPOSITE_LIST;
|
||||||
|
|
||||||
if ((ret.datasz + ret.ptrsz) * ret.len != e - d) {
|
if ((ret.datasz + ret.ptrsz) * ret.len != e - d) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e - s->data > s->len)
|
if (e - s->data > s->len)
|
||||||
|
|
@ -399,12 +411,11 @@ err:
|
||||||
|
|
||||||
capn_ptr capn_getp(capn_ptr p, int off) {
|
capn_ptr capn_getp(capn_ptr p, int off) {
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
/* Return an inner pointer */
|
/* Return an inner pointer */
|
||||||
if (off < p.len) {
|
if (off < p.len) {
|
||||||
capn_ptr ret = {CAPN_NULL};
|
capn_ptr ret = {CAPN_LIST_MEMBER};
|
||||||
ret.type = CAPN_STRUCT;
|
|
||||||
ret.is_list_member = 1;
|
|
||||||
ret.data = p.data + off * (p.datasz + p.ptrsz);
|
ret.data = p.data + off * (p.datasz + p.ptrsz);
|
||||||
ret.seg = p.seg;
|
ret.seg = p.seg;
|
||||||
ret.datasz = p.datasz;
|
ret.datasz = p.datasz;
|
||||||
|
|
@ -414,6 +425,8 @@ capn_ptr capn_getp(capn_ptr p, int off) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CAPN_INTERFACE:
|
||||||
|
case CAPN_LIST_MEMBER:
|
||||||
case CAPN_STRUCT:
|
case CAPN_STRUCT:
|
||||||
off *= 8;
|
off *= 8;
|
||||||
if (off >= p.ptrsz) {
|
if (off >= p.ptrsz) {
|
||||||
|
|
@ -438,27 +451,53 @@ err:
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t ptr_value(capn_ptr p, int off) {
|
static int data_size(struct capn_ptr p) {
|
||||||
|
switch (p.type) {
|
||||||
|
case CAPN_BIT_LIST:
|
||||||
|
return p.datasz;
|
||||||
|
case CAPN_PTR_LIST:
|
||||||
|
return p.len*8;
|
||||||
|
case CAPN_INTERFACE:
|
||||||
|
case CAPN_STRUCT:
|
||||||
|
return p.datasz + p.ptrsz;
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
|
return p.len * (p.datasz + p.ptrsz) + 8;
|
||||||
|
case CAPN_LIST:
|
||||||
|
return p.len * (p.datasz + p.ptrsz);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_ptr_tag(char *d, capn_ptr p, int off) {
|
||||||
uint64_t val = U64(U32(I32(off/8) << 2));
|
uint64_t val = U64(U32(I32(off/8) << 2));
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
|
case CAPN_INTERFACE:
|
||||||
|
val |= INTERFACE_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrsz/8) << 48);
|
||||||
|
break;
|
||||||
|
|
||||||
case CAPN_STRUCT:
|
case CAPN_STRUCT:
|
||||||
val |= STRUCT_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrsz/8) << 48);
|
val |= STRUCT_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrsz/8) << 48);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
|
val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p.len * (p.datasz + p.ptrsz)/8) << 35);
|
||||||
|
break;
|
||||||
|
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
if (p.has_composite_tag) {
|
val |= LIST_PTR | (U64(p.len) << 35);
|
||||||
val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p.len * (p.datasz + p.ptrsz)/8) << 35);
|
|
||||||
} else if (p.datasz == 8) {
|
if (p.datasz == 8) {
|
||||||
val |= LIST_PTR | (U64(BYTE_8_LIST) << 32) | (U64(p.len) << 35);
|
val |= (U64(BYTE_8_LIST) << 32);
|
||||||
} else if (p.datasz == 4) {
|
} else if (p.datasz == 4) {
|
||||||
val |= LIST_PTR | (U64(BYTE_4_LIST) << 32) | (U64(p.len) << 35);
|
val |= (U64(BYTE_4_LIST) << 32);
|
||||||
} else if (p.datasz == 2) {
|
} else if (p.datasz == 2) {
|
||||||
val |= LIST_PTR | (U64(BYTE_2_LIST) << 32) | (U64(p.len) << 35);
|
val |= (U64(BYTE_2_LIST) << 32);
|
||||||
} else if (p.datasz == 1) {
|
} else if (p.datasz == 1) {
|
||||||
val |= LIST_PTR | (U64(BYTE_1_LIST) << 32) | (U64(p.len) << 35);
|
val |= (U64(BYTE_1_LIST) << 32);
|
||||||
} else {
|
} else {
|
||||||
val |= LIST_PTR | (U64(VOID_LIST) << 32) | (U64(p.len) << 35);
|
val |= (U64(VOID_LIST) << 32);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -475,7 +514,7 @@ static uint64_t ptr_value(capn_ptr p, int off) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return capn_flip64(val);
|
*(uint64_t*) d = capn_flip64(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_far_ptr(char *d, struct capn_segment *s, char *tgt) {
|
static void write_far_ptr(char *d, struct capn_segment *s, char *tgt) {
|
||||||
|
|
@ -486,25 +525,17 @@ static void write_double_far(char *d, struct capn_segment *s, char *tgt) {
|
||||||
*(uint64_t*) d = capn_flip64(DOUBLE_PTR | U64(tgt - s->data) | (U64(s->id) << 32));
|
*(uint64_t*) d = capn_flip64(DOUBLE_PTR | U64(tgt - s->data) | (U64(s->id) << 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_ptr_tag(char *d, capn_ptr p, int off) {
|
|
||||||
*(uint64_t*) d = ptr_value(p, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NEED_TO_COPY 1
|
#define NEED_TO_COPY 1
|
||||||
|
|
||||||
static int write_ptr(struct capn_segment *s, char *d, capn_ptr p) {
|
static int write_ptr(struct capn_segment *s, char *d, capn_ptr p) {
|
||||||
/* note p.seg can be NULL if its a ptr to static data */
|
/* note p.seg can be NULL if its a ptr to static data */
|
||||||
char *pdata = p.data;
|
char *pdata = p.data - (p.type == CAPN_COMPOSITE_LIST ? 8 : 0);
|
||||||
|
|
||||||
if (p.has_composite_tag) {
|
if (data_size(p) == 0) {
|
||||||
pdata -= 8;
|
write_ptr_tag(d, p, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (p.type == CAPN_NULL) {
|
|
||||||
*(uint64_t*) d = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else if (!p.seg || p.seg->capn != s->capn || p.is_list_member) {
|
} else if (!p.seg || p.seg->capn != s->capn || p.type == CAPN_LIST_MEMBER) {
|
||||||
return NEED_TO_COPY;
|
return NEED_TO_COPY;
|
||||||
|
|
||||||
} else if (p.seg == s) {
|
} else if (p.seg == s) {
|
||||||
|
|
@ -559,30 +590,19 @@ struct copy {
|
||||||
char *fbegin, *fend;
|
char *fbegin, *fend;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int data_size(const struct capn_ptr *p) {
|
|
||||||
switch (p->type) {
|
|
||||||
case CAPN_BIT_LIST:
|
|
||||||
return p->datasz;
|
|
||||||
case CAPN_PTR_LIST:
|
|
||||||
return p->len*8;
|
|
||||||
case CAPN_STRUCT:
|
|
||||||
return p->datasz + p->ptrsz;
|
|
||||||
case CAPN_LIST:
|
|
||||||
return p->len * (p->datasz + p->ptrsz);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static capn_ptr new_clone(struct capn_segment *s, capn_ptr p) {
|
static capn_ptr new_clone(struct capn_segment *s, capn_ptr p) {
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
|
case CAPN_INTERFACE:
|
||||||
|
return capn_new_interface(s, p.datasz, p.ptrsz/8);
|
||||||
case CAPN_STRUCT:
|
case CAPN_STRUCT:
|
||||||
|
case CAPN_LIST_MEMBER:
|
||||||
return capn_new_struct(s, p.datasz, p.ptrsz/8);
|
return capn_new_struct(s, p.datasz, p.ptrsz/8);
|
||||||
case CAPN_PTR_LIST:
|
case CAPN_PTR_LIST:
|
||||||
return capn_new_ptr_list(s, p.len);
|
return capn_new_ptr_list(s, p.len);
|
||||||
case CAPN_BIT_LIST:
|
case CAPN_BIT_LIST:
|
||||||
return capn_new_list1(s, p.len).p;
|
return capn_new_list1(s, p.len).p;
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
return capn_new_list(s, p.len, p.datasz, p.ptrsz/8);
|
return capn_new_list(s, p.len, p.datasz, p.ptrsz/8);
|
||||||
default:
|
default:
|
||||||
return p;
|
return p;
|
||||||
|
|
@ -594,22 +614,15 @@ static int is_ptr_equal(const struct capn_ptr *a, const struct capn_ptr *b) {
|
||||||
&& a->type == b->type
|
&& a->type == b->type
|
||||||
&& a->len == b->len
|
&& a->len == b->len
|
||||||
&& a->datasz == b->datasz
|
&& a->datasz == b->datasz
|
||||||
&& a->ptrsz == b->ptrsz
|
&& a->ptrsz == b->ptrsz;
|
||||||
&& a->has_composite_tag == b->has_composite_tag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, struct capn_ptr *f, int *dep) {
|
static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, struct capn_ptr *f, int *dep) {
|
||||||
struct capn *c = seg->capn;
|
struct capn *c = seg->capn;
|
||||||
struct copy *cp = NULL;
|
struct copy *cp = NULL;
|
||||||
struct capn_tree **xcp;
|
struct capn_tree **xcp;
|
||||||
char *fbegin = f->data;
|
char *fbegin = f->data - (f->type == CAPN_COMPOSITE_LIST ? 8 : 0);
|
||||||
char *fend = fbegin + data_size(f);
|
char *fend = fbegin + data_size(*f);
|
||||||
|
|
||||||
if (f->has_composite_tag) {
|
|
||||||
fbegin -= 8;
|
|
||||||
} else if (f->is_list_member) {
|
|
||||||
fend = fbegin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We always copy list members as it would otherwise be an
|
/* We always copy list members as it would otherwise be an
|
||||||
* overlapped pointer (the data is owned by the enclosing list).
|
* overlapped pointer (the data is owned by the enclosing list).
|
||||||
|
|
@ -678,6 +691,7 @@ static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, st
|
||||||
* be valid */
|
* be valid */
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
case CAPN_STRUCT:
|
case CAPN_STRUCT:
|
||||||
|
case CAPN_INTERFACE:
|
||||||
if (t->datasz) {
|
if (t->datasz) {
|
||||||
memcpy(t->data, f->data, t->datasz);
|
memcpy(t->data, f->data, t->datasz);
|
||||||
t->data += t->datasz;
|
t->data += t->datasz;
|
||||||
|
|
@ -695,6 +709,7 @@ static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, st
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
|
case CAPN_COMPOSITE_LIST:
|
||||||
if (!t->len) {
|
if (!t->len) {
|
||||||
/* empty list - nothing to copy */
|
/* empty list - nothing to copy */
|
||||||
} else if (t->ptrsz && t->datasz) {
|
} else if (t->ptrsz && t->datasz) {
|
||||||
|
|
@ -748,7 +763,8 @@ int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
|
||||||
|
|
||||||
switch (p.type) {
|
switch (p.type) {
|
||||||
case CAPN_LIST:
|
case CAPN_LIST:
|
||||||
if (off >= p.len || tgt.type != CAPN_STRUCT)
|
case CAPN_COMPOSITE_LIST:
|
||||||
|
if (off >= p.len || (tgt.type != CAPN_STRUCT && tgt.type != CAPN_LIST_MEMBER))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
to[0] = p;
|
to[0] = p;
|
||||||
|
|
@ -764,6 +780,8 @@ int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
|
||||||
goto copy_ptr;
|
goto copy_ptr;
|
||||||
|
|
||||||
case CAPN_STRUCT:
|
case CAPN_STRUCT:
|
||||||
|
case CAPN_INTERFACE:
|
||||||
|
case CAPN_LIST_MEMBER:
|
||||||
off *= 8;
|
off *= 8;
|
||||||
if (off >= p.ptrsz)
|
if (off >= p.ptrsz)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -805,8 +823,7 @@ int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tc->type) {
|
if (tc->type == CAPN_COMPOSITE_LIST) {
|
||||||
case CAPN_LIST:
|
|
||||||
*fn = capn_getp(*fc, 0);
|
*fn = capn_getp(*fc, 0);
|
||||||
*tn = capn_getp(*tc, 0);
|
*tn = capn_getp(*tc, 0);
|
||||||
|
|
||||||
|
|
@ -815,10 +832,8 @@ int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
|
||||||
fc->data += fc->datasz + fc->ptrsz;
|
fc->data += fc->datasz + fc->ptrsz;
|
||||||
tc->data += tc->datasz + tc->ptrsz;
|
tc->data += tc->datasz + tc->ptrsz;
|
||||||
tc->len--;
|
tc->len--;
|
||||||
break;
|
|
||||||
|
|
||||||
case CAPN_PTR_LIST:
|
} else { /* CAPN_PTR_LIST */
|
||||||
default:
|
|
||||||
*fn = read_ptr(fc->seg, fc->data);
|
*fn = read_ptr(fc->seg, fc->data);
|
||||||
|
|
||||||
if (fn->type && copy_ptr(tc->seg, tc->data, tn, fn, &dep))
|
if (fn->type && copy_ptr(tc->seg, tc->data, tn, fn, &dep))
|
||||||
|
|
@ -827,7 +842,6 @@ int capn_setp(capn_ptr p, int off, capn_ptr tgt) {
|
||||||
fc->data += 8;
|
fc->data += 8;
|
||||||
tc->data += 8;
|
tc->data += 8;
|
||||||
tc->len--;
|
tc->len--;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -914,6 +928,9 @@ int capn_setv1(capn_list1 l, int off, const uint8_t *data, int sz) {
|
||||||
static void new_object(capn_ptr *p, int bytes) {
|
static void new_object(capn_ptr *p, int bytes) {
|
||||||
struct capn_segment *s = p->seg;
|
struct capn_segment *s = p->seg;
|
||||||
|
|
||||||
|
if (!bytes)
|
||||||
|
return;
|
||||||
|
|
||||||
/* all allocations are 8 byte aligned */
|
/* all allocations are 8 byte aligned */
|
||||||
bytes = (bytes + 7) & ~7;
|
bytes = (bytes + 7) & ~7;
|
||||||
|
|
||||||
|
|
@ -954,9 +971,17 @@ capn_ptr capn_root(struct capn *c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) {
|
capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) {
|
||||||
capn_ptr p = {CAPN_NULL};
|
capn_ptr p = {CAPN_STRUCT};
|
||||||
|
p.seg = seg;
|
||||||
|
p.datasz = (datasz + 7) & ~7;
|
||||||
|
p.ptrsz = ptrs * 8;
|
||||||
|
new_object(&p, p.datasz + p.ptrsz);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
capn_ptr capn_new_interface(struct capn_segment *seg, int datasz, int ptrs) {
|
||||||
|
capn_ptr p = {CAPN_INTERFACE};
|
||||||
p.seg = seg;
|
p.seg = seg;
|
||||||
p.type = CAPN_STRUCT;
|
|
||||||
p.datasz = (datasz + 7) & ~7;
|
p.datasz = (datasz + 7) & ~7;
|
||||||
p.ptrsz = ptrs * 8;
|
p.ptrsz = ptrs * 8;
|
||||||
new_object(&p, p.datasz + p.ptrsz);
|
new_object(&p, p.datasz + p.ptrsz);
|
||||||
|
|
@ -964,15 +989,16 @@ capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) {
|
capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) {
|
||||||
capn_ptr p = {CAPN_NULL};
|
capn_ptr p = {CAPN_LIST};
|
||||||
p.seg = seg;
|
p.seg = seg;
|
||||||
p.type = CAPN_LIST;
|
|
||||||
p.len = sz;
|
p.len = sz;
|
||||||
|
|
||||||
if (ptrs || datasz > 8) {
|
if (!sz) {
|
||||||
|
/* empty lists may as well be a len=0 void list */
|
||||||
|
} else if (ptrs || datasz > 8) {
|
||||||
|
p.type = CAPN_COMPOSITE_LIST;
|
||||||
p.datasz = (datasz + 7) & ~7;
|
p.datasz = (datasz + 7) & ~7;
|
||||||
p.ptrsz = ptrs*8;
|
p.ptrsz = ptrs*8;
|
||||||
p.has_composite_tag = 1;
|
|
||||||
new_object(&p, p.len * (p.datasz + p.ptrsz) + 8);
|
new_object(&p, p.len * (p.datasz + p.ptrsz) + 8);
|
||||||
if (p.data) {
|
if (p.data) {
|
||||||
uint64_t hdr = STRUCT_PTR | (U64(p.len) << 2) | (U64(p.datasz/8) << 32) | (U64(ptrs) << 48);
|
uint64_t hdr = STRUCT_PTR | (U64(p.len) << 2) | (U64(p.datasz/8) << 32) | (U64(ptrs) << 48);
|
||||||
|
|
@ -994,9 +1020,8 @@ capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capn_list1 capn_new_list1(struct capn_segment *seg, int sz) {
|
capn_list1 capn_new_list1(struct capn_segment *seg, int sz) {
|
||||||
capn_list1 l = {{CAPN_NULL}};
|
capn_list1 l = {{CAPN_BIT_LIST}};
|
||||||
l.p.seg = seg;
|
l.p.seg = seg;
|
||||||
l.p.type = CAPN_BIT_LIST;
|
|
||||||
l.p.datasz = (sz+7)/8;
|
l.p.datasz = (sz+7)/8;
|
||||||
l.p.len = sz;
|
l.p.len = sz;
|
||||||
new_object(&l.p, l.p.datasz);
|
new_object(&l.p, l.p.datasz);
|
||||||
|
|
@ -1004,9 +1029,8 @@ capn_list1 capn_new_list1(struct capn_segment *seg, int sz) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) {
|
capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) {
|
||||||
capn_ptr p = {CAPN_NULL};
|
capn_ptr p = {CAPN_PTR_LIST};
|
||||||
p.seg = seg;
|
p.seg = seg;
|
||||||
p.type = CAPN_PTR_LIST;
|
|
||||||
p.len = sz;
|
p.len = sz;
|
||||||
p.ptrsz = 0;
|
p.ptrsz = 0;
|
||||||
p.datasz = 0;
|
p.datasz = 0;
|
||||||
|
|
@ -1015,9 +1039,8 @@ capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz) {
|
capn_ptr capn_new_string(struct capn_segment *seg, const char *str, int sz) {
|
||||||
capn_ptr p = {CAPN_NULL};
|
capn_ptr p = {CAPN_LIST};
|
||||||
p.seg = seg;
|
p.seg = seg;
|
||||||
p.type = CAPN_LIST;
|
|
||||||
p.len = ((sz >= 0) ? sz : strlen(str)) + 1;
|
p.len = ((sz >= 0) ? sz : strlen(str)) + 1;
|
||||||
p.datasz = 1;
|
p.datasz = 1;
|
||||||
new_object(&p, p.len);
|
new_object(&p, p.len);
|
||||||
|
|
|
||||||
10
capn.h
10
capn.h
|
|
@ -87,14 +87,15 @@ enum CAPN_TYPE {
|
||||||
CAPN_STRUCT = 1,
|
CAPN_STRUCT = 1,
|
||||||
CAPN_LIST = 2,
|
CAPN_LIST = 2,
|
||||||
CAPN_PTR_LIST = 3,
|
CAPN_PTR_LIST = 3,
|
||||||
CAPN_BIT_LIST = 4
|
CAPN_BIT_LIST = 4,
|
||||||
|
CAPN_INTERFACE = 5,
|
||||||
|
CAPN_LIST_MEMBER = 6,
|
||||||
|
CAPN_COMPOSITE_LIST = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
struct capn_ptr {
|
struct capn_ptr {
|
||||||
unsigned int type : 3;
|
unsigned int type : 4;
|
||||||
unsigned int is_list_member : 1;
|
|
||||||
unsigned int has_ptr_tag : 1;
|
unsigned int has_ptr_tag : 1;
|
||||||
unsigned int has_composite_tag : 1;
|
|
||||||
unsigned int datasz : 19;
|
unsigned int datasz : 19;
|
||||||
unsigned int ptrsz : 19;
|
unsigned int ptrsz : 19;
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -176,6 +177,7 @@ int capn_setv64(capn_list64 p, int off, const uint64_t *data, int sz);
|
||||||
* On an error a CAPN_NULL pointer is returned
|
* On an error a CAPN_NULL pointer is returned
|
||||||
*/
|
*/
|
||||||
capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs);
|
capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs);
|
||||||
|
capn_ptr capn_new_interface(struct capn_segment *seg, int datasz, int ptrs);
|
||||||
capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs);
|
capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs);
|
||||||
capn_list1 capn_new_list1(struct capn_segment *seg, int sz);
|
capn_list1 capn_new_list1(struct capn_segment *seg, int sz);
|
||||||
capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz);
|
capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz);
|
||||||
|
|
|
||||||
|
|
@ -288,9 +288,8 @@ static void decode_value(struct value* v, Type_ptr type, Value_ptr value, const
|
||||||
if (strcmp(v->t.name, "capn_ptr"))
|
if (strcmp(v->t.name, "capn_ptr"))
|
||||||
str_addf(&SRC, "{");
|
str_addf(&SRC, "{");
|
||||||
|
|
||||||
str_addf(&SRC, "%d,%d,%d,%d,%d,%d,%d,(char*)&capn_buf[%d],(struct capn_segment*)&capn_seg",
|
str_addf(&SRC, "%d,%d,%d,%d,%d,(char*)&capn_buf[%d],(struct capn_segment*)&capn_seg",
|
||||||
p.type, p.is_list_member,
|
p.type, p.has_ptr_tag,
|
||||||
p.has_ptr_tag, p.has_composite_tag,
|
|
||||||
p.datasz, p.ptrsz,
|
p.datasz, p.ptrsz,
|
||||||
p.len, (int) (p.data-p.seg->data-8));
|
p.len, (int) (p.data-p.seg->data-8));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue