Commit eab15190 authored by Kenton Varda's avatar Kenton Varda

Runtime support and tests for inline lists.

parent 13ab0872
...@@ -594,6 +594,184 @@ TEST(Encoding, InlineDefaults) { ...@@ -594,6 +594,184 @@ TEST(Encoding, InlineDefaults) {
EXPECT_EQ("qux", unions.getUnion3().getF16p().getP0()); EXPECT_EQ("qux", unions.getUnion3().getF16p().getP0());
EXPECT_EQ("quux", unions.getUnion3().getF16p().getP1()); EXPECT_EQ("quux", unions.getUnion3().getF16p().getP1());
} }
{
auto lists = reader.getLists();
ASSERT_EQ(2u, lists.getVoidList().size());
ASSERT_EQ(3u, lists.getBoolList().size());
ASSERT_EQ(4u, lists.getUInt8List().size());
ASSERT_EQ(5u, lists.getUInt16List().size());
ASSERT_EQ(6u, lists.getUInt32List().size());
ASSERT_EQ(7u, lists.getUInt64List().size());
ASSERT_EQ(8u, lists.getTextList().size());
ASSERT_EQ(2u, lists.getStructList0().size());
ASSERT_EQ(3u, lists.getStructList1().size());
ASSERT_EQ(4u, lists.getStructList8().size());
ASSERT_EQ(2u, lists.getStructList16().size());
ASSERT_EQ(3u, lists.getStructList32().size());
ASSERT_EQ(4u, lists.getStructList64().size());
ASSERT_EQ(2u, lists.getStructList128().size());
ASSERT_EQ(3u, lists.getStructList192().size());
ASSERT_EQ(4u, lists.getStructList0p().size());
ASSERT_EQ(2u, lists.getStructList1p().size());
ASSERT_EQ(3u, lists.getStructList8p().size());
ASSERT_EQ(4u, lists.getStructList16p().size());
ASSERT_EQ(2u, lists.getStructList32p().size());
ASSERT_EQ(3u, lists.getStructList64p().size());
ASSERT_EQ(4u, lists.getStructList128p().size());
ASSERT_EQ(2u, lists.getStructList192p().size());
EXPECT_EQ(Void::VOID, lists.getVoidList()[0]);
EXPECT_EQ(Void::VOID, lists.getVoidList()[1]);
EXPECT_FALSE(lists.getBoolList()[0]);
EXPECT_TRUE(lists.getBoolList()[1]);
EXPECT_FALSE(lists.getBoolList()[2]);
EXPECT_EQ(12u, lists.getUInt8List()[0]);
EXPECT_EQ(34u, lists.getUInt8List()[1]);
EXPECT_EQ(56u, lists.getUInt8List()[2]);
EXPECT_EQ(78u, lists.getUInt8List()[3]);
EXPECT_EQ(1234u, lists.getUInt16List()[0]);
EXPECT_EQ(5678u, lists.getUInt16List()[1]);
EXPECT_EQ(9012u, lists.getUInt16List()[2]);
EXPECT_EQ(3456u, lists.getUInt16List()[3]);
EXPECT_EQ(7890u, lists.getUInt16List()[4]);
EXPECT_EQ(123456789u, lists.getUInt32List()[0]);
EXPECT_EQ(234567890u, lists.getUInt32List()[1]);
EXPECT_EQ(345678901u, lists.getUInt32List()[2]);
EXPECT_EQ(456789012u, lists.getUInt32List()[3]);
EXPECT_EQ(567890123u, lists.getUInt32List()[4]);
EXPECT_EQ(678901234u, lists.getUInt32List()[5]);
for (uint i = 0; i < 7; i++) {
EXPECT_EQ(i + 1, lists.getUInt64List()[i]);
}
EXPECT_EQ("foo", lists.getTextList()[0]);
EXPECT_EQ("bar", lists.getTextList()[1]);
EXPECT_EQ("baz", lists.getTextList()[2]);
EXPECT_EQ("qux", lists.getTextList()[3]);
EXPECT_EQ("quux", lists.getTextList()[4]);
EXPECT_EQ("corge", lists.getTextList()[5]);
EXPECT_EQ("grault", lists.getTextList()[6]);
EXPECT_EQ("garply", lists.getTextList()[7]);
EXPECT_EQ(Void::VOID, lists.getStructList0()[0].getF());
EXPECT_EQ(Void::VOID, lists.getStructList0()[1].getF());
EXPECT_TRUE(lists.getStructList1()[0].getF());
EXPECT_FALSE(lists.getStructList1()[1].getF());
// EXPECT_TRUE(lists.getStructList1()[2].getF());
EXPECT_TRUE (lists.getStructList8()[0].getF0());
EXPECT_FALSE(lists.getStructList8()[0].getF1());
EXPECT_FALSE(lists.getStructList8()[0].getF2());
EXPECT_FALSE(lists.getStructList8()[1].getF0());
EXPECT_TRUE (lists.getStructList8()[1].getF1());
EXPECT_FALSE(lists.getStructList8()[1].getF2());
EXPECT_TRUE (lists.getStructList8()[2].getF0());
EXPECT_TRUE (lists.getStructList8()[2].getF1());
EXPECT_FALSE(lists.getStructList8()[2].getF2());
EXPECT_FALSE(lists.getStructList8()[3].getF0());
EXPECT_FALSE(lists.getStructList8()[3].getF1());
EXPECT_TRUE (lists.getStructList8()[3].getF2());
EXPECT_EQ(12u, lists.getStructList16()[0].getF0());
EXPECT_EQ(34u, lists.getStructList16()[0].getF1());
EXPECT_EQ(56u, lists.getStructList16()[1].getF0());
EXPECT_EQ(78u, lists.getStructList16()[1].getF1());
EXPECT_EQ(90u, lists.getStructList32()[0].getF0());
EXPECT_EQ(12345u, lists.getStructList32()[0].getF1());
EXPECT_EQ(67u, lists.getStructList32()[1].getF0());
EXPECT_EQ(8901u, lists.getStructList32()[1].getF1());
EXPECT_EQ(23u, lists.getStructList32()[2].getF0());
EXPECT_EQ(45678u, lists.getStructList32()[2].getF1());
EXPECT_EQ(90u, lists.getStructList64()[0].getF0());
EXPECT_EQ(123456789u, lists.getStructList64()[0].getF1());
EXPECT_EQ(12u, lists.getStructList64()[1].getF0());
EXPECT_EQ(345678901u, lists.getStructList64()[1].getF1());
EXPECT_EQ(234u, lists.getStructList64()[2].getF0());
EXPECT_EQ(567890123u, lists.getStructList64()[2].getF1());
EXPECT_EQ(45u, lists.getStructList64()[3].getF0());
EXPECT_EQ(678901234u, lists.getStructList64()[3].getF1());
EXPECT_EQ(56789012345678ull, lists.getStructList128()[0].getF0());
EXPECT_EQ(90123456789012ull, lists.getStructList128()[0].getF1());
EXPECT_EQ(34567890123456ull, lists.getStructList128()[1].getF0());
EXPECT_EQ(78901234567890ull, lists.getStructList128()[1].getF1());
EXPECT_EQ(1234567890123ull, lists.getStructList192()[0].getF0());
EXPECT_EQ(4567890123456ull, lists.getStructList192()[0].getF1());
EXPECT_EQ(7890123456789ull, lists.getStructList192()[0].getF2());
EXPECT_EQ( 123456789012ull, lists.getStructList192()[1].getF0());
EXPECT_EQ(3456789012345ull, lists.getStructList192()[1].getF1());
EXPECT_EQ(6789012345678ull, lists.getStructList192()[1].getF2());
EXPECT_EQ(9012345678901ull, lists.getStructList192()[2].getF0());
EXPECT_EQ(2345678901234ull, lists.getStructList192()[2].getF1());
EXPECT_EQ(5678901234567ull, lists.getStructList192()[2].getF2());
EXPECT_EQ("foo", lists.getStructList0p()[0].getP0());
EXPECT_EQ("bar", lists.getStructList0p()[1].getP0());
EXPECT_EQ("baz", lists.getStructList0p()[2].getP0());
EXPECT_EQ("qux", lists.getStructList0p()[3].getP0());
EXPECT_TRUE(lists.getStructList1p()[0].getF().getF());
EXPECT_EQ("quux", lists.getStructList1p()[0].getP0());
EXPECT_EQ("corge", lists.getStructList1p()[1].getP0());
EXPECT_TRUE(lists.getStructList8p()[0].getF().getF0());
EXPECT_EQ("grault", lists.getStructList8p()[0].getP0());
EXPECT_EQ("garply", lists.getStructList8p()[1].getP0());
EXPECT_EQ("waldo", lists.getStructList8p()[2].getP0());
EXPECT_EQ(123u, lists.getStructList16p()[0].getF().getF0());
EXPECT_EQ("fred", lists.getStructList16p()[0].getP0());
EXPECT_EQ("plugh", lists.getStructList16p()[0].getP1());
EXPECT_EQ("xyzzy", lists.getStructList16p()[1].getP0());
EXPECT_EQ("thud", lists.getStructList16p()[1].getP1());
EXPECT_EQ("foobar", lists.getStructList16p()[2].getP0());
EXPECT_EQ("barbaz", lists.getStructList16p()[2].getP1());
EXPECT_EQ("bazqux", lists.getStructList16p()[3].getP0());
EXPECT_EQ("quxquux", lists.getStructList16p()[3].getP1());
EXPECT_EQ(12345u, lists.getStructList32p()[0].getF().getF1());
EXPECT_EQ("quuxcorge", lists.getStructList32p()[0].getP0());
EXPECT_EQ("corgegrault", lists.getStructList32p()[0].getP1());
EXPECT_EQ("graultgarply", lists.getStructList32p()[1].getP0());
EXPECT_EQ("garplywaldo", lists.getStructList32p()[1].getP1());
EXPECT_EQ(123456789u, lists.getStructList64p()[0].getF().getF1());
EXPECT_EQ("waldofred", lists.getStructList64p()[0].getP0());
EXPECT_EQ("fredplugh", lists.getStructList64p()[0].getP1());
EXPECT_EQ("plughxyzzy", lists.getStructList64p()[1].getP0());
EXPECT_EQ("xyzzythud", lists.getStructList64p()[1].getP1());
EXPECT_EQ("thudfoo", lists.getStructList64p()[2].getP0());
EXPECT_EQ("foofoo", lists.getStructList64p()[2].getP1());
EXPECT_EQ(123456789012345ull, lists.getStructList128p()[0].getF().getF1());
EXPECT_EQ("foobaz", lists.getStructList128p()[0].getP0());
EXPECT_EQ("fooqux", lists.getStructList128p()[0].getP1());
EXPECT_EQ("foocorge", lists.getStructList128p()[0].getP2());
EXPECT_EQ("barbaz", lists.getStructList128p()[1].getP0());
EXPECT_EQ("barqux", lists.getStructList128p()[1].getP1());
EXPECT_EQ("barcorge", lists.getStructList128p()[1].getP2());
EXPECT_EQ("bazbaz", lists.getStructList128p()[2].getP0());
EXPECT_EQ("bazqux", lists.getStructList128p()[2].getP1());
EXPECT_EQ("bazcorge", lists.getStructList128p()[2].getP2());
EXPECT_EQ("quxbaz", lists.getStructList128p()[3].getP0());
EXPECT_EQ("quxqux", lists.getStructList128p()[3].getP1());
EXPECT_EQ("quxcorge", lists.getStructList128p()[3].getP2());
EXPECT_EQ(123456789012345ull, lists.getStructList192p()[0].getF().getF2());
EXPECT_EQ("corgebaz", lists.getStructList192p()[0].getP0());
EXPECT_EQ("corgequx", lists.getStructList192p()[0].getP1());
EXPECT_EQ("corgecorge", lists.getStructList192p()[0].getP2());
EXPECT_EQ("graultbaz", lists.getStructList192p()[1].getP0());
EXPECT_EQ("graultqux", lists.getStructList192p()[1].getP1());
EXPECT_EQ("graultcorge", lists.getStructList192p()[1].getP2());
}
} }
// ======================================================================================= // =======================================================================================
......
...@@ -102,6 +102,8 @@ static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0, ...@@ -102,6 +102,8 @@ static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,
static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT = static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT =
{{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}};
static constexpr StructSize STRUCTLIST_ELEMENT_SIZE(1 * WORDS, 1 * REFERENCES, 64 * BITS);
static void setupStruct(StructBuilder builder) { static void setupStruct(StructBuilder builder) {
builder.setDataField<uint64_t>(0 * ELEMENTS, 0x1011121314151617ull); builder.setDataField<uint64_t>(0 * ELEMENTS, 0x1011121314151617ull);
builder.setDataField<uint32_t>(2 * ELEMENTS, 0x20212223u); builder.setDataField<uint32_t>(2 * ELEMENTS, 0x20212223u);
...@@ -118,7 +120,7 @@ static void setupStruct(StructBuilder builder) { ...@@ -118,7 +120,7 @@ static void setupStruct(StructBuilder builder) {
{ {
StructBuilder subStruct = builder.initStructField( StructBuilder subStruct = builder.initStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES)); 0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 64 * BITS));
subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123); subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123);
} }
...@@ -132,12 +134,12 @@ static void setupStruct(StructBuilder builder) { ...@@ -132,12 +134,12 @@ static void setupStruct(StructBuilder builder) {
{ {
ListBuilder list = builder.initStructListField( ListBuilder list = builder.initStructListField(
2 * REFERENCES, 4 * ELEMENTS, StructSize(1 * WORDS, 1 * REFERENCES)); 2 * REFERENCES, 4 * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
EXPECT_EQ(4 * ELEMENTS, list.size()); EXPECT_EQ(4 * ELEMENTS, list.size());
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
StructBuilder element = list.getStructElement(i * ELEMENTS, 2 * WORDS / ELEMENTS, 1 * WORDS); StructBuilder element = list.getStructElement(i * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
element.setDataField<int32_t>(0 * ELEMENTS, 300 + i); element.setDataField<int32_t>(0 * ELEMENTS, 300 + i);
element.initStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES)) element.initStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 64 * BITS))
.setDataField<int32_t>(0 * ELEMENTS, 400 + i); .setDataField<int32_t>(0 * ELEMENTS, 400 + i);
} }
} }
...@@ -147,7 +149,7 @@ static void setupStruct(StructBuilder builder) { ...@@ -147,7 +149,7 @@ static void setupStruct(StructBuilder builder) {
EXPECT_EQ(5 * ELEMENTS, list.size()); EXPECT_EQ(5 * ELEMENTS, list.size());
for (uint i = 0; i < 5; i++) { for (uint i = 0; i < 5; i++) {
ListBuilder element = list.initListElement( ListBuilder element = list.initListElement(
i * REFERENCES, FieldSize::TWO_BYTES, (i + 1) * ELEMENTS); i * ELEMENTS, FieldSize::TWO_BYTES, (i + 1) * ELEMENTS);
EXPECT_EQ((i + 1) * ELEMENTS, element.size()); EXPECT_EQ((i + 1) * ELEMENTS, element.size());
for (uint j = 0; j <= i; j++) { for (uint j = 0; j <= i; j++) {
element.setDataElement<uint16_t>(j * ELEMENTS, 500 + j); element.setDataElement<uint16_t>(j * ELEMENTS, 500 + j);
...@@ -172,7 +174,7 @@ static void checkStruct(StructBuilder builder) { ...@@ -172,7 +174,7 @@ static void checkStruct(StructBuilder builder) {
{ {
StructBuilder subStruct = builder.getStructField( StructBuilder subStruct = builder.getStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES), SUBSTRUCT_DEFAULT.words); 0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 64 * BITS), SUBSTRUCT_DEFAULT.words);
EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS)); EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS));
} }
...@@ -188,10 +190,10 @@ static void checkStruct(StructBuilder builder) { ...@@ -188,10 +190,10 @@ static void checkStruct(StructBuilder builder) {
ListBuilder list = builder.getListField(2 * REFERENCES, nullptr); ListBuilder list = builder.getListField(2 * REFERENCES, nullptr);
ASSERT_EQ(4 * ELEMENTS, list.size()); ASSERT_EQ(4 * ELEMENTS, list.size());
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
StructBuilder element = list.getStructElement(i * ELEMENTS, 2 * WORDS / ELEMENTS, 1 * WORDS); StructBuilder element = list.getStructElement(i * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS)); EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS));
EXPECT_EQ(400 + i, EXPECT_EQ(400 + i,
element.getStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES), element.getStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 64 * BITS),
STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words)
.getDataField<int32_t>(0 * ELEMENTS)); .getDataField<int32_t>(0 * ELEMENTS));
} }
...@@ -201,7 +203,7 @@ static void checkStruct(StructBuilder builder) { ...@@ -201,7 +203,7 @@ static void checkStruct(StructBuilder builder) {
ListBuilder list = builder.getListField(3 * REFERENCES, nullptr); ListBuilder list = builder.getListField(3 * REFERENCES, nullptr);
ASSERT_EQ(5 * ELEMENTS, list.size()); ASSERT_EQ(5 * ELEMENTS, list.size());
for (uint i = 0; i < 5; i++) { for (uint i = 0; i < 5; i++) {
ListBuilder element = list.getListElement(i * REFERENCES); ListBuilder element = list.getListElement(i * ELEMENTS);
ASSERT_EQ((i + 1) * ELEMENTS, element.size()); ASSERT_EQ((i + 1) * ELEMENTS, element.size());
for (uint j = 0; j <= i; j++) { for (uint j = 0; j <= i; j++) {
EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS));
...@@ -254,7 +256,7 @@ static void checkStruct(StructReader reader) { ...@@ -254,7 +256,7 @@ static void checkStruct(StructReader reader) {
ListReader list = reader.getListField(3 * REFERENCES, FieldSize::REFERENCE, nullptr); ListReader list = reader.getListField(3 * REFERENCES, FieldSize::REFERENCE, nullptr);
ASSERT_EQ(5 * ELEMENTS, list.size()); ASSERT_EQ(5 * ELEMENTS, list.size());
for (uint i = 0; i < 5; i++) { for (uint i = 0; i < 5; i++) {
ListReader element = list.getListElement(i * REFERENCES, FieldSize::TWO_BYTES); ListReader element = list.getListElement(i * ELEMENTS, FieldSize::TWO_BYTES);
ASSERT_EQ((i + 1) * ELEMENTS, element.size()); ASSERT_EQ((i + 1) * ELEMENTS, element.size());
for (uint j = 0; j <= i; j++) { for (uint j = 0; j <= i; j++) {
EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS));
...@@ -270,7 +272,7 @@ TEST(WireFormat, StructRoundTrip_OneSegment) { ...@@ -270,7 +272,7 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot( StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES)); segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder); setupStruct(builder);
// word count: // word count:
...@@ -306,7 +308,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { ...@@ -306,7 +308,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot( StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES)); segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder); setupStruct(builder);
// Verify that we made 15 segments. // Verify that we made 15 segments.
...@@ -343,7 +345,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { ...@@ -343,7 +345,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot( StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES)); segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder); setupStruct(builder);
// Verify that we made 6 segments. // Verify that we made 6 segments.
......
...@@ -415,7 +415,8 @@ struct WireHelpers { ...@@ -415,7 +415,8 @@ struct WireHelpers {
ref->structRef.set(size); ref->structRef.set(size);
// Build the StructBuilder. // Build the StructBuilder.
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data), 0 * BITS); return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data), 0 * BITS,
size.pointers);
} }
static CAPNPROTO_ALWAYS_INLINE(StructBuilder getWritableStructReference( static CAPNPROTO_ALWAYS_INLINE(StructBuilder getWritableStructReference(
...@@ -442,7 +443,8 @@ struct WireHelpers { ...@@ -442,7 +443,8 @@ struct WireHelpers {
"Trying to update struct with incorrect reference count."); "Trying to update struct with incorrect reference count.");
} }
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data), 0 * BITS); return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data), 0 * BITS,
size.pointers);
} }
static CAPNPROTO_ALWAYS_INLINE(ListBuilder initListReference( static CAPNPROTO_ALWAYS_INLINE(ListBuilder initListReference(
...@@ -451,9 +453,10 @@ struct WireHelpers { ...@@ -451,9 +453,10 @@ struct WireHelpers {
DPRECOND(elementSize != FieldSize::INLINE_COMPOSITE, DPRECOND(elementSize != FieldSize::INLINE_COMPOSITE,
"Should have called initStructListReference() instead."); "Should have called initStructListReference() instead.");
auto step = bitsPerElement(elementSize);
// Calculate size of the list. // Calculate size of the list.
WordCount wordCount = roundUpToWords( WordCount wordCount = roundUpToWords(ElementCount64(elementCount) * step);
ElementCount64(elementCount) * bitsPerElement(elementSize));
// Allocate the list. // Allocate the list.
word* ptr = allocate(ref, segment, wordCount, WireReference::LIST); word* ptr = allocate(ref, segment, wordCount, WireReference::LIST);
...@@ -462,12 +465,33 @@ struct WireHelpers { ...@@ -462,12 +465,33 @@ struct WireHelpers {
ref->listRef.set(elementSize, elementCount); ref->listRef.set(elementSize, elementCount);
// Build the ListBuilder. // Build the ListBuilder.
return ListBuilder(segment, ptr, elementCount); return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr),
step, step / BITS_PER_REFERENCE, elementCount);
} }
static CAPNPROTO_ALWAYS_INLINE(ListBuilder initStructListReference( static CAPNPROTO_ALWAYS_INLINE(ListBuilder initStructListReference(
WireReference* ref, SegmentBuilder* segment, ElementCount elementCount, WireReference* ref, SegmentBuilder* segment, ElementCount elementCount,
StructSize elementSize)) { StructSize elementSize)) {
if ((elementSize.pointers == 0 * REFERENCES && elementSize.data <= 1 * WORDS) ||
(elementSize.pointers == 1 * REFERENCES && elementSize.data == 0 * WORDS)) {
// Small data-only struct. Allocate a list of primitives instead.
FieldSize primitiveElementSize = FieldSize::VOID;
if (elementSize.pointers == 1 * REFERENCES) {
primitiveElementSize = FieldSize::REFERENCE;
} else {
switch (elementSize.dataBits / BITS) {
case 0: primitiveElementSize = FieldSize::VOID; break;
case 1: primitiveElementSize = FieldSize::BIT; break;
case 8: primitiveElementSize = FieldSize::BYTE; break;
case 16: primitiveElementSize = FieldSize::TWO_BYTES; break;
case 32: primitiveElementSize = FieldSize::FOUR_BYTES; break;
case 64: primitiveElementSize = FieldSize::EIGHT_BYTES; break;
default: FAIL_PRECOND("Invalid struct size."); break;
}
}
return initListReference(ref, segment, elementCount, primitiveElementSize);
}
auto wordsPerElement = elementSize.total() / ELEMENTS; auto wordsPerElement = elementSize.total() / ELEMENTS;
// Allocate the list, prefixed by a single WireReference. // Allocate the list, prefixed by a single WireReference.
...@@ -485,7 +509,9 @@ struct WireHelpers { ...@@ -485,7 +509,9 @@ struct WireHelpers {
ptr += REFERENCE_SIZE_IN_WORDS; ptr += REFERENCE_SIZE_IN_WORDS;
// Build the ListBuilder. // Build the ListBuilder.
return ListBuilder(segment, ptr, elementCount); return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + elementSize.data),
wordsPerElement * BITS_PER_WORD, wordsPerElement / WORDS_PER_REFERENCE,
elementCount);
} }
static CAPNPROTO_ALWAYS_INLINE(ListBuilder getWritableListReference( static CAPNPROTO_ALWAYS_INLINE(ListBuilder getWritableListReference(
...@@ -495,7 +521,8 @@ struct WireHelpers { ...@@ -495,7 +521,8 @@ struct WireHelpers {
if (ref->isNull()) { if (ref->isNull()) {
if (defaultValue == nullptr) { if (defaultValue == nullptr) {
return ListBuilder(segment, nullptr, 0 * ELEMENTS); return ListBuilder(segment, nullptr, nullptr, 0 * BITS / ELEMENTS,
0 * REFERENCES / ELEMENTS, 0 * ELEMENTS);
} }
ptr = copyMessage(segment, ref, defaultRef); ptr = copyMessage(segment, ref, defaultRef);
} else { } else {
...@@ -510,12 +537,19 @@ struct WireHelpers { ...@@ -510,12 +537,19 @@ struct WireHelpers {
WireReference* tag = reinterpret_cast<WireReference*>(ptr); WireReference* tag = reinterpret_cast<WireReference*>(ptr);
PRECOND(tag->kind() == WireReference::STRUCT, PRECOND(tag->kind() == WireReference::STRUCT,
"INLINE_COMPOSITE list with non-STRUCT elements not supported."); "INLINE_COMPOSITE list with non-STRUCT elements not supported.");
ElementCount elementCount = tag->inlineCompositeListElementCount();
// First list element is at tag + 1 reference. // First list element is at tag + 1 reference.
return ListBuilder(segment, reinterpret_cast<word*>(tag + 1), elementCount); word* data = reinterpret_cast<word*>(tag + 1);
WireReference* pointers = reinterpret_cast<WireReference*>(
data + tag->structRef.dataSize.get());
auto step = tag->structRef.wordSize() / ELEMENTS;
return ListBuilder(segment, data, pointers, step * BITS_PER_WORD, step / WORDS_PER_REFERENCE,
tag->inlineCompositeListElementCount());
} else { } else {
return ListBuilder(segment, ptr, ref->listRef.elementCount()); decltype(BITS/ELEMENTS) step = bitsPerElement(ref->listRef.elementSize());
return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr),
step, step / BITS_PER_REFERENCE,
ref->listRef.elementCount());
} }
} }
...@@ -649,7 +683,9 @@ struct WireHelpers { ...@@ -649,7 +683,9 @@ struct WireHelpers {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
if (defaultValue == nullptr) { if (defaultValue == nullptr) {
return ListReader(nullptr, nullptr, 0 * ELEMENTS, 0 * BITS / ELEMENTS, nestingLimit - 1); return ListReader(nullptr, nullptr, nullptr, 0 * ELEMENTS,
0 * BITS / ELEMENTS, 0 * REFERENCES / ELEMENTS,
nestingLimit - 1);
} }
segment = nullptr; segment = nullptr;
ref = reinterpret_cast<const WireReference*>(defaultValue); ref = reinterpret_cast<const WireReference*>(defaultValue);
...@@ -751,7 +787,10 @@ struct WireHelpers { ...@@ -751,7 +787,10 @@ struct WireHelpers {
} }
} }
return ListReader(segment, ptr, size, wordsPerElement * BITS_PER_WORD, return ListReader(
segment, ptr,
reinterpret_cast<const WireReference*>(ptr + tag->structRef.dataSize.get()),
size, wordsPerElement * BITS_PER_WORD, wordsPerElement / WORDS_PER_REFERENCE,
tag->structRef.dataSize.get() * BITS_PER_WORD, tag->structRef.dataSize.get() * BITS_PER_WORD,
tag->structRef.refCount.get(), nestingLimit - 1); tag->structRef.refCount.get(), nestingLimit - 1);
...@@ -768,7 +807,9 @@ struct WireHelpers { ...@@ -768,7 +807,9 @@ struct WireHelpers {
} }
if (ref->listRef.elementSize() == expectedElementSize) { if (ref->listRef.elementSize() == expectedElementSize) {
return ListReader(segment, ptr, ref->listRef.elementCount(), step, nestingLimit - 1); return ListReader(segment, ptr, reinterpret_cast<const WireReference*>(ptr),
ref->listRef.elementCount(), step, step / BITS_PER_REFERENCE,
nestingLimit - 1);
} else if (expectedElementSize == FieldSize::INLINE_COMPOSITE) { } else if (expectedElementSize == FieldSize::INLINE_COMPOSITE) {
// We were expecting a struct list, but we received a list of some other type. Perhaps a // We were expecting a struct list, but we received a list of some other type. Perhaps a
// non-struct list was recently upgraded to a struct list, but the sender is using the // non-struct list was recently upgraded to a struct list, but the sender is using the
...@@ -792,7 +833,8 @@ struct WireHelpers { ...@@ -792,7 +833,8 @@ struct WireHelpers {
break; break;
} }
return ListReader(segment, ptr, ref->listRef.elementCount(), step, return ListReader(segment, ptr, reinterpret_cast<const WireReference*>(ptr),
ref->listRef.elementCount(), step, step / BITS_PER_REFERENCE,
dataSize, referenceCount, nestingLimit - 1); dataSize, referenceCount, nestingLimit - 1);
} else { } else {
PRECOND(segment != nullptr, "Trusted message had incompatible list element type."); PRECOND(segment != nullptr, "Trusted message had incompatible list element type.");
...@@ -1017,101 +1059,102 @@ Data::Reader StructReader::getDataField( ...@@ -1017,101 +1059,102 @@ Data::Reader StructReader::getDataField(
return WireHelpers::readDataReference(segment, ref, defaultValue, defaultSize); return WireHelpers::readDataReference(segment, ref, defaultValue, defaultSize);
} }
StructBuilder ListBuilder::getStructElement( StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const {
ElementCount index, decltype(WORDS/ELEMENTS) elementSize, WordCount structDataSize) const { // TODO: Inline this method?
word* structPtr = ptr + elementSize * index; BitCount64 indexBit = ElementCount64(index) * stepBits;
return StructBuilder(segment, structPtr, byte* structData = reinterpret_cast<byte*>(data) + indexBit / BITS_PER_BYTE;
reinterpret_cast<WireReference*>(structPtr + structDataSize), 0 * BITS); WireReference* structPointers = pointers + index * stepPointers;
return StructBuilder(segment, structData, structPointers, indexBit % BITS_PER_BYTE,
elementSize.pointers);
} }
ListBuilder ListBuilder::initListElement( ListBuilder ListBuilder::initListElement(
WireReferenceCount index, FieldSize elementSize, ElementCount elementCount) const { ElementCount index, FieldSize elementSize, ElementCount elementCount) const {
return WireHelpers::initListReference( return WireHelpers::initListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, pointers + index * stepPointers, segment,
elementCount, elementSize); elementCount, elementSize);
} }
ListBuilder ListBuilder::initStructListElement( ListBuilder ListBuilder::initStructListElement(
WireReferenceCount index, ElementCount elementCount, StructSize elementSize) const { ElementCount index, ElementCount elementCount, StructSize elementSize) const {
return WireHelpers::initStructListReference( return WireHelpers::initStructListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, pointers + index * stepPointers, segment,
elementCount, elementSize); elementCount, elementSize);
} }
ListBuilder ListBuilder::getListElement(WireReferenceCount index) const { ListBuilder ListBuilder::getListElement(ElementCount index) const {
return WireHelpers::getWritableListReference( return WireHelpers::getWritableListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, nullptr); pointers + index * stepPointers, segment, nullptr);
} }
Text::Builder ListBuilder::initTextElement(WireReferenceCount index, ByteCount size) const { Text::Builder ListBuilder::initTextElement(ElementCount index, ByteCount size) const {
return WireHelpers::initTextReference( return WireHelpers::initTextReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, size); pointers + index * stepPointers, segment, size);
} }
void ListBuilder::setTextElement(WireReferenceCount index, Text::Reader value) const { void ListBuilder::setTextElement(ElementCount index, Text::Reader value) const {
WireHelpers::setTextReference( WireHelpers::setTextReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, value); pointers + index * stepPointers, segment, value);
} }
Text::Builder ListBuilder::getTextElement(WireReferenceCount index) const { Text::Builder ListBuilder::getTextElement(ElementCount index) const {
return WireHelpers::getWritableTextReference( return WireHelpers::getWritableTextReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, "", 0 * BYTES); pointers + index * stepPointers, segment, "", 0 * BYTES);
} }
Data::Builder ListBuilder::initDataElement(WireReferenceCount index, ByteCount size) const { Data::Builder ListBuilder::initDataElement(ElementCount index, ByteCount size) const {
return WireHelpers::initDataReference( return WireHelpers::initDataReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, size); pointers + index * stepPointers, segment, size);
} }
void ListBuilder::setDataElement(WireReferenceCount index, Data::Reader value) const { void ListBuilder::setDataElement(ElementCount index, Data::Reader value) const {
WireHelpers::setDataReference( WireHelpers::setDataReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, value); pointers + index * stepPointers, segment, value);
} }
Data::Builder ListBuilder::getDataElement(WireReferenceCount index) const { Data::Builder ListBuilder::getDataElement(ElementCount index) const {
return WireHelpers::getWritableDataReference( return WireHelpers::getWritableDataReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, nullptr, 0 * BYTES); pointers + index * stepPointers, segment, nullptr, 0 * BYTES);
} }
ListReader ListBuilder::asReader(FieldSize elementSize) const { ListReader ListBuilder::asReader(FieldSize elementSize) const {
// TODO: For INLINE_COMPOSITE I suppose we could just check the tag? // TODO: For INLINE_COMPOSITE I suppose we could just check the tag?
PRECOND(elementSize != FieldSize::INLINE_COMPOSITE, PRECOND(elementSize != FieldSize::INLINE_COMPOSITE,
"Need to call the other asReader() overload for INLINE_COMPOSITE lists."); "Need to call the other asReader() overload for INLINE_COMPOSITE lists.");
return ListReader(segment, ptr, elementCount, bitsPerElement(elementSize), return ListReader(segment, data, pointers, elementCount, stepBits, stepPointers,
std::numeric_limits<int>::max()); std::numeric_limits<int>::max());
} }
ListReader ListBuilder::asReader(BitCount dataSize, WireReferenceCount referenceCount) const { ListReader ListBuilder::asReader(StructSize elementSize) const {
return ListReader(segment, ptr, elementCount, return ListReader(segment, data, pointers, elementCount, stepBits, stepPointers,
(dataSize + referenceCount * WORDS_PER_REFERENCE * BITS_PER_WORD) / ELEMENTS, elementSize.dataBits, elementSize.pointers, std::numeric_limits<int>::max());
dataSize, referenceCount, std::numeric_limits<int>::max());
} }
StructReader ListReader::getStructElement(ElementCount index) const { StructReader ListReader::getStructElement(ElementCount index) const {
// TODO: Inline this method?
VALIDATE_INPUT((segment == nullptr) | (nestingLimit > 0), VALIDATE_INPUT((segment == nullptr) | (nestingLimit > 0),
"Message is too deeply-nested or contains cycles. See capnproto::ReadOptions.") { "Message is too deeply-nested or contains cycles. See capnproto::ReadOptions.") {
return StructReader::readEmpty(); return StructReader::readEmpty();
} }
BitCount64 indexBit = ElementCount64(index) * stepBits; BitCount64 indexBit = ElementCount64(index) * stepBits;
const byte* structPtr = reinterpret_cast<const byte*>(ptr) + indexBit / BITS_PER_BYTE; const byte* structData = reinterpret_cast<const byte*>(data) + indexBit / BITS_PER_BYTE;
return StructReader( return StructReader(
segment, structPtr, segment, structData, pointers + index * stepPointers,
reinterpret_cast<const WireReference*>(structPtr + structDataSize / BITS_PER_BYTE),
structDataSize, structReferenceCount, indexBit % BITS_PER_BYTE, nestingLimit - 1); structDataSize, structReferenceCount, indexBit % BITS_PER_BYTE, nestingLimit - 1);
} }
ListReader ListReader::getListElement( ListReader ListReader::getListElement(
WireReferenceCount index, FieldSize expectedElementSize) const { ElementCount index, FieldSize expectedElementSize) const {
return WireHelpers::readListReference( return WireHelpers::readListReference(
segment, reinterpret_cast<const WireReference*>(ptr) + index, segment, pointers + index * stepPointers,
nullptr, expectedElementSize, nestingLimit); nullptr, expectedElementSize, nestingLimit);
} }
Text::Reader ListReader::getTextElement(WireReferenceCount index) const { Text::Reader ListReader::getTextElement(ElementCount index) const {
return WireHelpers::readTextReference(segment, return WireHelpers::readTextReference(
reinterpret_cast<const WireReference*>(ptr) + index, "", 0 * BYTES); segment, pointers + index * stepPointers, "", 0 * BYTES);
} }
Data::Reader ListReader::getDataElement(WireReferenceCount index) const { Data::Reader ListReader::getDataElement(ElementCount index) const {
return WireHelpers::readDataReference(segment, return WireHelpers::readDataReference(
reinterpret_cast<const WireReference*>(ptr) + index, nullptr, 0 * BYTES); segment, pointers + index * stepPointers, nullptr, 0 * BYTES);
} }
} // namespace internal } // namespace internal
......
...@@ -132,11 +132,15 @@ struct StructSize { ...@@ -132,11 +132,15 @@ struct StructSize {
WordCount16 data; WordCount16 data;
WireReferenceCount16 pointers; WireReferenceCount16 pointers;
BitCount32 dataBits;
// If data == 1 word, dataBits may be 1, 8, 16, 32, or 64. Otherwise, it is data * BITS_PER_WORD.
// This is used when packing inline structs.
inline constexpr WordCount total() const { return data + pointers * WORDS_PER_REFERENCE; } inline constexpr WordCount total() const { return data + pointers * WORDS_PER_REFERENCE; }
StructSize() = default; StructSize() = default;
inline constexpr StructSize(WordCount data, WireReferenceCount pointers) inline constexpr StructSize(WordCount data, WireReferenceCount pointers, BitCount dataBits)
: data(data), pointers(pointers) {} : data(data), pointers(pointers), dataBits(dataBits) {}
}; };
template <typename T> template <typename T>
...@@ -307,6 +311,34 @@ public: ...@@ -307,6 +311,34 @@ public:
// already allocated, it is allocated as a deep copy of the given default value (a trusted // already allocated, it is allocated as a deep copy of the given default value (a trusted
// message). If the default value is null, an empty list is used. // message). If the default value is null, an empty list is used.
CAPNPROTO_ALWAYS_INLINE(ListBuilder initInlineDataListField(
BitCount offset, BitCount inlineSize,
ElementCount elementCount, FieldSize elementSize) const);
// Initialize an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListBuilder initInlinePointerListField(
WireReferenceCount offset, WireReferenceCount inlineSize,
ElementCount elementCount) const);
// Initialize an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListBuilder initInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const);
// Initialize an inline struct list field.
CAPNPROTO_ALWAYS_INLINE(ListBuilder getInlineDataListField(
BitCount offset, ElementCount elementCount, FieldSize elementSize) const);
// Get an already-initialized inline list field.
CAPNPROTO_ALWAYS_INLINE(ListBuilder getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const);
// Get an already-initialized inline list field.
CAPNPROTO_ALWAYS_INLINE(ListBuilder getInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const);
// Get an already-initialized inline struct list field.
Text::Builder initTextField(WireReferenceCount refIndex, ByteCount size) const; Text::Builder initTextField(WireReferenceCount refIndex, ByteCount size) const;
// Initialize the text field to the given size in bytes (not including NUL terminator) and return // Initialize the text field to the given size in bytes (not including NUL terminator) and return
// a Text::Builder which can be used to fill in the content. // a Text::Builder which can be used to fill in the content.
...@@ -327,6 +359,8 @@ public: ...@@ -327,6 +359,8 @@ public:
StructReader asReader() const; StructReader asReader() const;
// Gets a StructReader pointing at the same memory. // Gets a StructReader pointing at the same memory.
WireReferenceCount getReferenceCount() { return referenceCount; }
private: private:
SegmentBuilder* segment; // Memory segment in which the struct resides. SegmentBuilder* segment; // Memory segment in which the struct resides.
void* data; // Pointer to the encoded data. void* data; // Pointer to the encoded data.
...@@ -336,9 +370,13 @@ private: ...@@ -336,9 +370,13 @@ private:
// A special hack: When accessing a boolean with field number zero, pretend its offset is this // A special hack: When accessing a boolean with field number zero, pretend its offset is this
// instead of the usual zero. This is needed to support 1-bit inline structs. // instead of the usual zero. This is needed to support 1-bit inline structs.
WireReferenceCount16 referenceCount;
// Size of the pointer segment, available only for the sake of computing size of List(Inline(T)).
inline StructBuilder(SegmentBuilder* segment, void* data, WireReference* references, inline StructBuilder(SegmentBuilder* segment, void* data, WireReference* references,
BitCount8 bit0Offset) BitCount8 bit0Offset, WireReferenceCount referenceCount)
: segment(segment), data(data), references(references), bit0Offset(bit0Offset) {} : segment(segment), data(data), references(references), bit0Offset(bit0Offset),
referenceCount(referenceCount) {}
friend class ListBuilder; friend class ListBuilder;
friend struct WireHelpers; friend struct WireHelpers;
...@@ -382,6 +420,19 @@ public: ...@@ -382,6 +420,19 @@ public:
// Get the list field at the given index in the reference segment, or the default value if not // Get the list field at the given index in the reference segment, or the default value if not
// initialized. The default value is allowed to be null, in which case an empty list is used. // initialized. The default value is allowed to be null, in which case an empty list is used.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlineDataListField(
BitCount offset, ElementCount elementCount, FieldSize elementSize) const);
// Get an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const);
// Get an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const);
// Get an inline struct list field.
Text::Reader getTextField(WireReferenceCount refIndex, Text::Reader getTextField(WireReferenceCount refIndex,
const void* defaultValue, ByteCount defaultSize) const; const void* defaultValue, ByteCount defaultSize) const;
// Gets the text field, or the given default value if not initialized. // Gets the text field, or the given default value if not initialized.
...@@ -390,6 +441,8 @@ public: ...@@ -390,6 +441,8 @@ public:
const void* defaultValue, ByteCount defaultSize) const; const void* defaultValue, ByteCount defaultSize) const;
// Gets the data field, or the given default value if not initialized. // Gets the data field, or the given default value if not initialized.
WireReferenceCount getReferenceCount() { return referenceCount; }
private: private:
SegmentReader* segment; // Memory segment in which the struct resides. SegmentReader* segment; // Memory segment in which the struct resides.
...@@ -425,7 +478,9 @@ private: ...@@ -425,7 +478,9 @@ private:
class ListBuilder { class ListBuilder {
public: public:
inline ListBuilder(): segment(nullptr), ptr(nullptr), elementCount(0) {} inline ListBuilder()
: segment(nullptr), data(nullptr), pointers(nullptr), elementCount(0 * ELEMENTS),
stepBits(0 * BITS / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS) {}
inline ElementCount size(); inline ElementCount size();
// The number of elements in the list. // The number of elements in the list.
...@@ -439,52 +494,61 @@ public: ...@@ -439,52 +494,61 @@ public:
ElementCount index, typename NoInfer<T>::Type value) const); ElementCount index, typename NoInfer<T>::Type value) const);
// Set the element at the given index. // Set the element at the given index.
StructBuilder getStructElement( StructBuilder getStructElement(ElementCount index, StructSize elementSize) const;
ElementCount index, decltype(WORDS/ELEMENTS) elementSize, WordCount structDataSize) const; // Get the struct element at the given index.
// Get the struct element at the given index. elementSize is the size, in 64-bit words, of
// each element.
ListBuilder initListElement( ListBuilder initListElement(
WireReferenceCount index, FieldSize elementSize, ElementCount elementCount) const; ElementCount index, FieldSize elementSize, ElementCount elementCount) const;
// Create a new list element of the given size at the given index. All elements are initialized // Create a new list element of the given size at the given index. All elements are initialized
// to zero. // to zero.
ListBuilder initStructListElement(WireReferenceCount index, ElementCount elementCount, ListBuilder initStructListElement(ElementCount index, ElementCount elementCount,
StructSize size) const; StructSize size) const;
// Allocates a new list of the given size for the field at the given index in the reference // Allocates a new list of the given size for the field at the given index in the reference
// segment, and return a pointer to it. Each element is initialized to its empty state. // segment, and return a pointer to it. Each element is initialized to its empty state.
ListBuilder getListElement(WireReferenceCount index) const; ListBuilder getListElement(ElementCount index) const;
// Get the existing list element at the given index. Returns an empty list if the element is // Get the existing list element at the given index. Returns an empty list if the element is
// not initialized. // not initialized.
Text::Builder initTextElement(WireReferenceCount index, ByteCount size) const; Text::Builder initTextElement(ElementCount index, ByteCount size) const;
// Initialize the text element to the given size in bytes (not including NUL terminator) and // Initialize the text element to the given size in bytes (not including NUL terminator) and
// return a Text::Builder which can be used to fill in the content. // return a Text::Builder which can be used to fill in the content.
void setTextElement(WireReferenceCount index, Text::Reader value) const; void setTextElement(ElementCount index, Text::Reader value) const;
// Set the text element to a copy of the given text. // Set the text element to a copy of the given text.
Text::Builder getTextElement(WireReferenceCount index) const; Text::Builder getTextElement(ElementCount index) const;
// Get the text element. If it is not initialized, returns an empty Text::Builder. // Get the text element. If it is not initialized, returns an empty Text::Builder.
Data::Builder initDataElement(WireReferenceCount index, ByteCount size) const; Data::Builder initDataElement(ElementCount index, ByteCount size) const;
void setDataElement(WireReferenceCount index, Data::Reader value) const; void setDataElement(ElementCount index, Data::Reader value) const;
Data::Builder getDataElement(WireReferenceCount index) const; Data::Builder getDataElement(ElementCount index) const;
ListReader asReader(FieldSize elementSize) const; ListReader asReader(FieldSize elementSize) const;
// Get a ListReader pointing at the same memory. Use this version only for non-struct lists. // Get a ListReader pointing at the same memory. Use this version only for non-struct lists.
ListReader asReader(BitCount dataSize, WireReferenceCount referenceCount) const; ListReader asReader(StructSize elementSize) const;
// Get a ListReader pointing at the same memory. Use this version only for struct lists. // Get a ListReader pointing at the same memory. Use this version only for struct lists.
private: private:
SegmentBuilder* segment; // Memory segment in which the list resides. SegmentBuilder* segment; // Memory segment in which the list resides.
word* ptr; // Pointer to the beginning of the list.
void* data;
WireReference* pointers;
// Pointers to list content.
ElementCount elementCount; // Number of elements in the list. ElementCount elementCount; // Number of elements in the list.
inline ListBuilder(SegmentBuilder* segment, word* ptr, ElementCount size) decltype(BITS / ELEMENTS) stepBits;
: segment(segment), ptr(ptr), elementCount(size) {} decltype(REFERENCES / ELEMENTS) stepPointers;
// The distance between elements. Can be tricky e.g. for inlined struct lists.
inline ListBuilder(SegmentBuilder* segment, void* data, WireReference* pointers,
decltype(BITS / ELEMENTS) stepBits,
decltype(REFERENCES / ELEMENTS) stepPointers, ElementCount size)
: segment(segment), data(data), pointers(pointers), elementCount(size),
stepBits(stepBits), stepPointers(stepPointers) {}
friend class StructBuilder; friend class StructBuilder;
friend struct WireHelpers; friend struct WireHelpers;
...@@ -493,9 +557,9 @@ private: ...@@ -493,9 +557,9 @@ private:
class ListReader { class ListReader {
public: public:
inline ListReader() inline ListReader()
: segment(nullptr), ptr(nullptr), elementCount(0), : segment(nullptr), data(nullptr), pointers(nullptr), elementCount(0),
stepBits(0 * BITS / ELEMENTS), structDataSize(0), stepBits(0 * BITS / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS),
structReferenceCount(0), nestingLimit(0) {} structDataSize(0), structReferenceCount(0), nestingLimit(0) {}
inline ElementCount size(); inline ElementCount size();
// The number of elements in the list. // The number of elements in the list.
...@@ -507,50 +571,49 @@ public: ...@@ -507,50 +571,49 @@ public:
StructReader getStructElement(ElementCount index) const; StructReader getStructElement(ElementCount index) const;
// Get the struct element at the given index. // Get the struct element at the given index.
ListReader getListElement(WireReferenceCount index, FieldSize expectedElementSize) const; ListReader getListElement(ElementCount index, FieldSize expectedElementSize) const;
// Get the list element at the given index. // Get the list element at the given index.
Text::Reader getTextElement(WireReferenceCount index) const; Text::Reader getTextElement(ElementCount index) const;
// Get the text element. If it is not initialized, returns an empty Text::Reader. // Get the text element. If it is not initialized, returns an empty Text::Reader.
Data::Reader getDataElement(WireReferenceCount index) const; Data::Reader getDataElement(ElementCount index) const;
// Get the data element. If it is not initialized, returns an empty Data::Reader. // Get the data element. If it is not initialized, returns an empty Data::Reader.
private: private:
SegmentReader* segment; // Memory segment in which the list resides. SegmentReader* segment; // Memory segment in which the list resides.
const void* ptr; const void* data;
// Pointer to the data. If null, use defaultReferences. (Never null for data lists.) const WireReference* pointers;
// Must be aligned appropriately for the elements. // Pointers to list content.
ElementCount elementCount; // Number of elements in the list. ElementCount elementCount; // Number of elements in the list.
decltype(BITS / ELEMENTS) stepBits; decltype(BITS / ELEMENTS) stepBits;
// The distance between elements, in bits. This is usually the element size, but can be larger decltype(REFERENCES / ELEMENTS) stepPointers;
// if the sender upgraded a data list to a struct list. It will always be aligned properly for // The distance between elements. Can be tricky e.g. for inlined struct lists.
// the type. Unsigned so that division by a constant power of 2 is efficient.
BitCount structDataSize; BitCount structDataSize;
WireReferenceCount structReferenceCount; WireReferenceCount structReferenceCount;
// If the elements are structs, the properties of the struct. The reference count is // If the elements are structs, the properties of the struct.
// only used to check for field presence; the data size is also used to compute the reference
// pointer.
int nestingLimit; int nestingLimit;
// Limits the depth of message structures to guard against stack-overflow-based DoS attacks. // Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
// Once this reaches zero, further pointers will be pruned. // Once this reaches zero, further pointers will be pruned.
inline ListReader(SegmentReader* segment, const void* ptr, ElementCount elementCount, inline ListReader(SegmentReader* segment, const void* data, const WireReference* pointers,
decltype(BITS / ELEMENTS) stepBits, int nestingLimit) ElementCount elementCount, decltype(BITS / ELEMENTS) stepBits,
: segment(segment), ptr(ptr), elementCount(elementCount), stepBits(stepBits), decltype(REFERENCES / ELEMENTS) stepPointers, int nestingLimit)
structDataSize(0), structReferenceCount(0), : segment(segment), data(data), pointers(pointers), elementCount(elementCount),
stepBits(stepBits), stepPointers(stepPointers), structDataSize(0), structReferenceCount(0),
nestingLimit(nestingLimit) {} nestingLimit(nestingLimit) {}
inline ListReader(SegmentReader* segment, const void* ptr, ElementCount elementCount, inline ListReader(SegmentReader* segment, const void* data, const WireReference* pointers,
decltype(BITS / ELEMENTS) stepBits, BitCount structDataSize, ElementCount elementCount, decltype(BITS / ELEMENTS) stepBits,
decltype(REFERENCES / ELEMENTS) stepPointers, BitCount structDataSize,
WireReferenceCount structReferenceCount, int nestingLimit) WireReferenceCount structReferenceCount, int nestingLimit)
: segment(segment), ptr(ptr), elementCount(elementCount), stepBits(stepBits), : segment(segment), data(data), pointers(pointers), elementCount(elementCount),
structDataSize(structDataSize), structReferenceCount(structReferenceCount), stepBits(stepBits), stepPointers(stepPointers), structDataSize(structDataSize),
nestingLimit(nestingLimit) {} structReferenceCount(structReferenceCount), nestingLimit(nestingLimit) {}
friend class StructReader; friend class StructReader;
friend class ListBuilder; friend class ListBuilder;
...@@ -637,14 +700,68 @@ inline StructBuilder StructBuilder::getInlineStructField( ...@@ -637,14 +700,68 @@ inline StructBuilder StructBuilder::getInlineStructField(
// WireReference is incomplete here so we have to cast around... Bah. // WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast<WireReference*>( reinterpret_cast<WireReference*>(
reinterpret_cast<word*>(references) + refIndex * WORDS_PER_REFERENCE), reinterpret_cast<word*>(references) + refIndex * WORDS_PER_REFERENCE),
dataOffset == 0 * BITS ? BitCount(bit0Offset) : dataOffset % BITS_PER_BYTE); dataOffset == 0 * BITS ? BitCount(bit0Offset) : dataOffset % BITS_PER_BYTE,
inlineRefCount);
}
inline ListBuilder StructBuilder::initInlineDataListField(
BitCount offset, BitCount inlineSize,
ElementCount elementCount, FieldSize elementSize) const {
memset(reinterpret_cast<byte*>(data) + offset / BITS_PER_BYTE, 0,
inlineSize / BITS_PER_BYTE / BYTES);
return getInlineDataListField(offset, elementCount, elementSize);
}
inline ListBuilder StructBuilder::initInlinePointerListField(
WireReferenceCount offset, WireReferenceCount inlineSize,
ElementCount elementCount) const {
memset(reinterpret_cast<word*>(references) + offset * WORDS_PER_REFERENCE, 0,
inlineSize * BYTES_PER_REFERENCE / BYTES);
return getInlinePointerListField(offset, elementCount);
}
inline ListBuilder StructBuilder::initInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const {
memset(reinterpret_cast<byte*>(data) + dataOffset / BITS_PER_BYTE, 0,
elementSize.dataBits / BITS_PER_BYTE / BYTES);
memset(reinterpret_cast<word*>(references) + ptrOffset * WORDS_PER_REFERENCE, 0,
elementSize.pointers * BYTES_PER_REFERENCE / BYTES);
return getInlineStructListField(dataOffset, ptrOffset, elementCount, elementSize);
}
inline ListBuilder StructBuilder::getInlineDataListField(
BitCount offset, ElementCount elementCount, FieldSize elementSize) const {
return ListBuilder(
segment, reinterpret_cast<byte*>(data) + offset / BITS_PER_BYTE, nullptr,
bitsPerElement(elementSize), 0 * REFERENCES / ELEMENTS, elementCount);
}
inline ListBuilder StructBuilder::getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const {
return ListBuilder(
segment, nullptr,
reinterpret_cast<WireReference*>(
reinterpret_cast<word*>(references) + offset * WORDS_PER_REFERENCE),
0 * BITS / ELEMENTS, 1 * REFERENCES / ELEMENTS, elementCount);
}
inline ListBuilder StructBuilder::getInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const {
return ListBuilder(
segment, reinterpret_cast<byte*>(data) + dataOffset / BITS_PER_BYTE,
reinterpret_cast<WireReference*>(
reinterpret_cast<word*>(references) + ptrOffset * WORDS_PER_REFERENCE),
elementSize.dataBits / ELEMENTS, elementSize.pointers / ELEMENTS,
elementCount);
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
template <typename T> template <typename T>
T StructReader::getDataField(ElementCount offset) const { T StructReader::getDataField(ElementCount offset) const {
if (offset * capnproto::bitsPerElement<T>() < dataSize) { if ((offset + 1 * ELEMENTS) * capnproto::bitsPerElement<T>() <= dataSize) {
return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get(); return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get();
} else { } else {
return static_cast<T>(0); return static_cast<T>(0);
...@@ -689,19 +806,49 @@ inline StructReader StructReader::getInlineStructField( ...@@ -689,19 +806,49 @@ inline StructReader StructReader::getInlineStructField(
nestingLimit); nestingLimit);
} }
inline ListReader StructReader::getInlineDataListField(
BitCount offset, ElementCount elementCount, FieldSize elementSize) const {
return ListReader(
segment, reinterpret_cast<const byte*>(data) + offset / BITS_PER_BYTE, nullptr,
elementCount, bitsPerElement(elementSize), 0 * REFERENCES / ELEMENTS,
nestingLimit);
}
inline ListReader StructReader::getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const {
return ListReader(
segment, nullptr,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + offset * WORDS_PER_REFERENCE),
elementCount, 0 * BITS / ELEMENTS, 1 * REFERENCES / ELEMENTS,
nestingLimit);
}
inline ListReader StructReader::getInlineStructListField(
BitCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const {
return ListReader(
segment, reinterpret_cast<const byte*>(data) + dataOffset / BITS_PER_BYTE,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + ptrOffset * WORDS_PER_REFERENCE),
elementCount, elementSize.dataBits / ELEMENTS, elementSize.pointers / ELEMENTS,
elementSize.dataBits, elementSize.pointers, nestingLimit);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline ElementCount ListBuilder::size() { return elementCount; } inline ElementCount ListBuilder::size() { return elementCount; }
template <typename T> template <typename T>
inline T ListBuilder::getDataElement(ElementCount index) const { inline T ListBuilder::getDataElement(ElementCount index) const {
return reinterpret_cast<WireValue<T>*>(ptr)[index / ELEMENTS].get(); return reinterpret_cast<WireValue<T>*>(
reinterpret_cast<byte*>(data) + index * stepBits / BITS_PER_BYTE)->get();
} }
template <> template <>
inline bool ListBuilder::getDataElement<bool>(ElementCount index) const { inline bool ListBuilder::getDataElement<bool>(ElementCount index) const {
BitCount bindex = index * (1 * BITS / ELEMENTS); BitCount bindex = index * stepBits;
byte* b = reinterpret_cast<byte*>(ptr) + bindex / BITS_PER_BYTE; byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
return (*reinterpret_cast<uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; return (*reinterpret_cast<uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0;
} }
...@@ -712,13 +859,14 @@ inline Void ListBuilder::getDataElement<Void>(ElementCount index) const { ...@@ -712,13 +859,14 @@ inline Void ListBuilder::getDataElement<Void>(ElementCount index) const {
template <typename T> template <typename T>
inline void ListBuilder::setDataElement(ElementCount index, typename NoInfer<T>::Type value) const { inline void ListBuilder::setDataElement(ElementCount index, typename NoInfer<T>::Type value) const {
reinterpret_cast<WireValue<T>*>(ptr)[index / ELEMENTS].set(value); reinterpret_cast<WireValue<T>*>(
reinterpret_cast<byte*>(data) + index * stepBits / BITS_PER_BYTE)->set(value);
} }
template <> template <>
inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) const { inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) const {
BitCount bindex = index * (1 * BITS / ELEMENTS); BitCount bindex = index * stepBits;
byte* b = reinterpret_cast<byte*>(ptr) + bindex / BITS_PER_BYTE; byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
uint bitnum = bindex % BITS_PER_BYTE / BITS; uint bitnum = bindex % BITS_PER_BYTE / BITS;
*reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum)) *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum))
| (static_cast<uint8_t>(value) << bitnum); | (static_cast<uint8_t>(value) << bitnum);
...@@ -733,14 +881,14 @@ inline ElementCount ListReader::size() { return elementCount; } ...@@ -733,14 +881,14 @@ inline ElementCount ListReader::size() { return elementCount; }
template <typename T> template <typename T>
inline T ListReader::getDataElement(ElementCount index) const { inline T ListReader::getDataElement(ElementCount index) const {
return *reinterpret_cast<const T*>( return reinterpret_cast<const WireValue<T>*>(
reinterpret_cast<const byte*>(ptr) + index * stepBits / BITS_PER_BYTE); reinterpret_cast<const byte*>(data) + index * stepBits / BITS_PER_BYTE)->get();
} }
template <> template <>
inline bool ListReader::getDataElement<bool>(ElementCount index) const { inline bool ListReader::getDataElement<bool>(ElementCount index) const {
BitCount bindex = index * stepBits; BitCount bindex = index * stepBits;
const byte* b = reinterpret_cast<const byte*>(ptr) + bindex / BITS_PER_BYTE; const byte* b = reinterpret_cast<const byte*>(data) + bindex / BITS_PER_BYTE;
return (*reinterpret_cast<const uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; return (*reinterpret_cast<const uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0;
} }
......
...@@ -236,8 +236,7 @@ struct List<T, false> { ...@@ -236,8 +236,7 @@ struct List<T, false> {
inline uint size() { return builder.size() / ELEMENTS; } inline uint size() { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) { inline typename T::Builder operator[](uint index) {
return typename T::Builder(builder.getStructElement(index * ELEMENTS, return typename T::Builder(builder.getStructElement(index * ELEMENTS, T::STRUCT_SIZE));
T::STRUCT_SIZE.total() / ELEMENTS, T::STRUCT_SIZE.data));
} }
typedef internal::IndexingIterator<Builder, typename T::Builder> iterator; typedef internal::IndexingIterator<Builder, typename T::Builder> iterator;
...@@ -282,11 +281,11 @@ struct List<List<T>, true> { ...@@ -282,11 +281,11 @@ struct List<List<T>, true> {
inline uint size() { return builder.size() / ELEMENTS; } inline uint size() { return builder.size() / ELEMENTS; }
inline typename List<T>::Builder operator[](uint index) { inline typename List<T>::Builder operator[](uint index) {
return typename List<T>::Builder(builder.getListElement(index * REFERENCES)); return typename List<T>::Builder(builder.getListElement(index * ELEMENTS));
} }
inline typename List<T>::Builder init(uint index, uint size) { inline typename List<T>::Builder init(uint index, uint size) {
return typename List<T>::Builder(builder.initListElement( return typename List<T>::Builder(builder.initListElement(
index * REFERENCES, internal::FieldSizeForType<T>::value, size * ELEMENTS)); index * ELEMENTS, internal::FieldSizeForType<T>::value, size * ELEMENTS));
} }
typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator; typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator;
...@@ -312,7 +311,7 @@ struct List<List<T>, false> { ...@@ -312,7 +311,7 @@ struct List<List<T>, false> {
inline uint size() { return reader.size() / ELEMENTS; } inline uint size() { return reader.size() / ELEMENTS; }
inline typename List<T>::Reader operator[](uint index) { inline typename List<T>::Reader operator[](uint index) {
return typename List<T>::Reader(reader.getListElement(index * REFERENCES, return typename List<T>::Reader(reader.getListElement(index * ELEMENTS,
internal::FieldSizeForType<T>::value)); internal::FieldSizeForType<T>::value));
} }
...@@ -331,11 +330,11 @@ struct List<List<T>, false> { ...@@ -331,11 +330,11 @@ struct List<List<T>, false> {
inline uint size() { return builder.size() / ELEMENTS; } inline uint size() { return builder.size() / ELEMENTS; }
inline typename List<T>::Builder operator[](uint index) { inline typename List<T>::Builder operator[](uint index) {
return typename List<T>::Builder(builder.getListElement(index * REFERENCES)); return typename List<T>::Builder(builder.getListElement(index * ELEMENTS));
} }
inline typename List<T>::Builder init(uint index, uint size) { inline typename List<T>::Builder init(uint index, uint size) {
return typename List<T>::Builder(builder.initStructListElement( return typename List<T>::Builder(builder.initStructListElement(
index * REFERENCES, size * ELEMENTS, T::DEFAULT.words)); index * ELEMENTS, size * ELEMENTS, T::DEFAULT.words));
} }
typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator; typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator;
...@@ -361,7 +360,7 @@ struct List<Data, false> { ...@@ -361,7 +360,7 @@ struct List<Data, false> {
inline uint size() { return reader.size() / ELEMENTS; } inline uint size() { return reader.size() / ELEMENTS; }
inline Data::Reader operator[](uint index) { inline Data::Reader operator[](uint index) {
return reader.getDataElement(index * REFERENCES); return reader.getDataElement(index * ELEMENTS);
} }
typedef internal::IndexingIterator<Reader, Data::Reader> iterator; typedef internal::IndexingIterator<Reader, Data::Reader> iterator;
...@@ -379,13 +378,13 @@ struct List<Data, false> { ...@@ -379,13 +378,13 @@ struct List<Data, false> {
inline uint size() { return builder.size() / ELEMENTS; } inline uint size() { return builder.size() / ELEMENTS; }
inline Data::Builder operator[](uint index) { inline Data::Builder operator[](uint index) {
return builder.getDataElement(index * REFERENCES); return builder.getDataElement(index * ELEMENTS);
} }
inline void set(uint index, Data::Reader value) { inline void set(uint index, Data::Reader value) {
builder.setDataElement(index * REFERENCES, value); builder.setDataElement(index * ELEMENTS, value);
} }
inline Data::Builder init(uint index, uint size) { inline Data::Builder init(uint index, uint size) {
return builder.initDataElement(index * REFERENCES, size * BYTES); return builder.initDataElement(index * ELEMENTS, size * BYTES);
} }
typedef internal::IndexingIterator<Builder, Data::Builder> iterator; typedef internal::IndexingIterator<Builder, Data::Builder> iterator;
...@@ -425,7 +424,7 @@ struct List<Text, false> { ...@@ -425,7 +424,7 @@ struct List<Text, false> {
inline uint size() { return reader.size() / ELEMENTS; } inline uint size() { return reader.size() / ELEMENTS; }
inline Text::Reader operator[](uint index) { inline Text::Reader operator[](uint index) {
return reader.getTextElement(index * REFERENCES); return reader.getTextElement(index * ELEMENTS);
} }
typedef internal::IndexingIterator<Reader, Text::Reader> iterator; typedef internal::IndexingIterator<Reader, Text::Reader> iterator;
...@@ -443,13 +442,13 @@ struct List<Text, false> { ...@@ -443,13 +442,13 @@ struct List<Text, false> {
inline uint size() { return builder.size() / ELEMENTS; } inline uint size() { return builder.size() / ELEMENTS; }
inline Text::Builder operator[](uint index) { inline Text::Builder operator[](uint index) {
return builder.getTextElement(index * REFERENCES); return builder.getTextElement(index * ELEMENTS);
} }
inline void set(uint index, Text::Reader value) { inline void set(uint index, Text::Reader value) {
builder.setTextElement(index * REFERENCES, value); builder.setTextElement(index * ELEMENTS, value);
} }
inline Text::Builder init(uint index, uint size) { inline Text::Builder init(uint index, uint size) {
return builder.initTextElement(index * REFERENCES, size * BYTES); return builder.initTextElement(index * ELEMENTS, size * BYTES);
} }
typedef internal::IndexingIterator<Builder, Text::Builder> iterator; typedef internal::IndexingIterator<Builder, Text::Builder> iterator;
......
...@@ -276,7 +276,7 @@ struct TestUsing { ...@@ -276,7 +276,7 @@ struct TestUsing {
innerNestedEnum @0 :NestedEnum = quux; innerNestedEnum @0 :NestedEnum = quux;
} }
struct TestInline0 fixed(0 bits) {} struct TestInline0 fixed(0 bits) { f @0: Void; }
struct TestInline1 fixed(1 bits) { f @0: Bool; } struct TestInline1 fixed(1 bits) { f @0: Bool; }
struct TestInline8 fixed(8 bits) { f0 @0: Bool; f1 @1: Bool; f2 @2: Bool; } struct TestInline8 fixed(8 bits) { f0 @0: Bool; f1 @1: Bool; f2 @2: Bool; }
struct TestInline16 fixed(16 bits) { f0 @0: UInt8; f1 @1: UInt8; } struct TestInline16 fixed(16 bits) { f0 @0: UInt8; f1 @1: UInt8; }
...@@ -384,9 +384,37 @@ struct TestInlineUnions { ...@@ -384,9 +384,37 @@ struct TestInlineUnions {
byte0 @39: UInt8; byte0 @39: UInt8;
} }
struct TestInlineLists {
voidList @ 0 : InlineList(Void, 2);
boolList @ 1 : InlineList(Bool, 3);
uInt8List @ 2 : InlineList(UInt8, 4);
uInt16List @ 3 : InlineList(UInt16, 5);
uInt32List @ 4 : InlineList(UInt32, 6);
uInt64List @ 5 : InlineList(UInt64, 7);
textList @ 6 : InlineList(Text, 8);
structList0 @ 7 : InlineList(TestInline0, 2);
structList1 @ 8 : InlineList(TestInline1, 3);
structList8 @ 9 : InlineList(TestInline8, 4);
structList16 @10 : InlineList(TestInline16, 2);
structList32 @11 : InlineList(TestInline32, 3);
structList64 @12 : InlineList(TestInline64, 4);
structList128 @13 : InlineList(TestInline128, 2);
structList192 @14 : InlineList(TestInline192, 3);
structList0p @15 : InlineList(TestInline0p, 4);
structList1p @16 : InlineList(TestInline1p, 2);
structList8p @17 : InlineList(TestInline8p, 3);
structList16p @18 : InlineList(TestInline16p, 4);
structList32p @19 : InlineList(TestInline32p, 2);
structList64p @20 : InlineList(TestInline64p, 3);
structList128p @21 : InlineList(TestInline128p, 4);
structList192p @22 : InlineList(TestInline192p, 2);
}
struct TestInlineDefaults { struct TestInlineDefaults {
normal @0 :TestInlineLayout = ( normal @0 :TestInlineLayout = (
f0 = (), f0 = (f = void),
f1 = (f = true), f1 = (f = true),
f8 = (f0 = true, f1 = false, f2 = true), f8 = (f0 = true, f1 = false, f2 = true),
f16 = (f0 = 123, f1 = 45), f16 = (f0 = 123, f1 = 45),
...@@ -411,4 +439,52 @@ struct TestInlineDefaults { ...@@ -411,4 +439,52 @@ struct TestInlineDefaults {
union1 = f128(f0 = 1234567890123, f1 = 4567890123456), union1 = f128(f0 = 1234567890123, f1 = 4567890123456),
union2 = f1p(p0 = "foo"), union2 = f1p(p0 = "foo"),
union3 = f16p(f = (f0 = 98, f1 = 76), p0 = "qux", p1 = "quux")); union3 = f16p(f = (f0 = 98, f1 = 76), p0 = "qux", p1 = "quux"));
lists @2 :TestInlineLists = (
voidList = [void, void],
boolList = [false, true, false],
uInt8List = [12, 34, 56, 78],
uInt16List = [1234, 5678, 9012, 3456, 7890],
uInt32List = [123456789, 234567890, 345678901, 456789012, 567890123, 678901234],
uInt64List = [1, 2, 3, 4, 5, 6, 7],
textList = ["foo", "bar", "baz", "qux", "quux", "corge", "grault", "garply"],
structList0 = [(f = void), ()],
structList1 = [(f = true), (f = false), (f = true)],
structList8 = [(f0 = true, f1 = false, f2 = false),
(f0 = false, f1 = true, f2 = false),
(f0 = true, f1 = true, f2 = false),
(f0 = false, f1 = false, f2 = true)],
structList16 = [(f0 = 12, f1 = 34), (f0 = 56, f1 = 78)],
structList32 = [(f0 = 90, f1 = 12345), (f0 = 67, f1 = 8901), (f0 = 23, f1 = 45678)],
structList64 = [(f0 = 90, f1 = 123456789), (f0 = 12, f1 = 345678901),
(f0 = 234, f1 = 567890123), (f0 = 45, f1 = 678901234)],
structList128 = [(f0 = 56789012345678, f1 = 90123456789012),
(f0 = 34567890123456, f1 = 78901234567890)],
structList192 = [(f0 = 1234567890123, f1 = 4567890123456, f2 = 7890123456789),
(f0 = 123456789012, f1 = 3456789012345, f2 = 6789012345678),
(f0 = 9012345678901, f1 = 2345678901234, f2 = 5678901234567)],
structList0p = [(f = (f = void), p0 = "foo"), (p0 = "bar"),
(f = (), p0 = "baz"), (p0 = "qux")],
structList1p = [(f = (f = true), p0 = "quux"), (p0 = "corge")],
structList8p = [(f = (f0 = true), p0 = "grault"), (p0 = "garply"), (p0 = "waldo")],
structList16p = [(f = (f0 = 123), p0 = "fred", p1 = "plugh"),
(p0 = "xyzzy", p1 = "thud"),
(p0 = "foobar", p1 = "barbaz"),
(p0 = "bazqux", p1 = "quxquux")],
structList32p = [(f = (f1 = 12345), p0 = "quuxcorge", p1 = "corgegrault"),
(p0 = "graultgarply", p1 = "garplywaldo")],
structList64p = [(f = (f1 = 123456789), p0 = "waldofred", p1 = "fredplugh"),
(p0 = "plughxyzzy", p1 = "xyzzythud"),
(p0 = "thudfoo", p1 = "foofoo")],
structList128p = [(f = (f1 = 123456789012345),
p0 = "foobaz", p1 = "fooqux", p2 = "foocorge"),
(p0 = "barbaz", p1 = "barqux", p2 = "barcorge"),
(p0 = "bazbaz", p1 = "bazqux", p2 = "bazcorge"),
(p0 = "quxbaz", p1 = "quxqux", p2 = "quxcorge")],
structList192p = [(f = (f2 = 123456789012345),
p0 = "corgebaz", p1 = "corgequx", p2 = "corgecorge"),
(p0 = "graultbaz", p1 = "graultqux", p2 = "graultcorge")]
);
} }
...@@ -326,6 +326,21 @@ public: ...@@ -326,6 +326,21 @@ public:
unit1PerUnit2 * other.unit1PerUnit2); unit1PerUnit2 * other.unit1PerUnit2);
} }
template <typename OtherNumber, typename Unit3>
inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2>
operator/(UnitRatio<OtherNumber, Unit1, Unit3> other) {
// (U1 / U2) / (U1 / U3) = U3 / U2
return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2>(
unit1PerUnit2 / other.unit1PerUnit2);
}
template <typename OtherNumber, typename Unit3>
inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3>
operator/(UnitRatio<OtherNumber, Unit3, Unit2> other) {
// (U1 / U2) / (U3 / U2) = U1 / U3
return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3>(
unit1PerUnit2 / other.unit1PerUnit2);
}
private: private:
Number unit1PerUnit2; Number unit1PerUnit2;
......
...@@ -295,7 +295,13 @@ compileType scope (TypeExpression n params) = do ...@@ -295,7 +295,13 @@ compileType scope (TypeExpression n params) = do
desc <- lookupDesc scope n desc <- lookupDesc scope n
case desc of case desc of
DescBuiltinList -> case params of DescBuiltinList -> case params of
[TypeParameterType param] -> fmap ListType (compileType scope param) [TypeParameterType param] -> do
inner <- compileType scope param
case inner of
InlineStructType _ -> makeError (declNamePos n)
"Don't declare list elements 'Inline'. The regular encoding for struct \
\lists already inlines the elements."
_ -> return (ListType inner)
_ -> makeError (declNamePos n) "'List' requires exactly one type parameter." _ -> makeError (declNamePos n) "'List' requires exactly one type parameter."
DescBuiltinInline -> case params of DescBuiltinInline -> case params of
[TypeParameterType param] -> do [TypeParameterType param] -> do
...@@ -311,7 +317,18 @@ compileType scope (TypeExpression n params) = do ...@@ -311,7 +317,18 @@ compileType scope (TypeExpression n params) = do
DescBuiltinInlineList -> case params of DescBuiltinInlineList -> case params of
[TypeParameterType param, TypeParameterInteger size] -> do [TypeParameterType param, TypeParameterInteger size] -> do
inner <- compileType scope param inner <- compileType scope param
return $ InlineListType inner size case inner of
InlineStructType _ -> makeError (declNamePos n)
"Don't declare list elements 'Inline'. The regular encoding for struct \
\lists already inlines the elements."
StructType s -> if structIsFixedWidth s
then return (InlineListType (InlineStructType s) size)
else makeError (declNamePos n) $
printf "'%s' cannot be inlined because it is not fixed-width."
(structName s)
InlineListType _ _ -> makeError (declNamePos n)
"InlineList of InlineList not currently supported."
_ -> return $ InlineListType inner size
_ -> makeError (declNamePos n) _ -> makeError (declNamePos n)
"'InlineList' requires exactly two type parameters: a type and a size." "'InlineList' requires exactly two type parameters: a type and a size."
_ -> case params of _ -> case params of
......
...@@ -105,17 +105,24 @@ isInlineStruct (InlineStructType _) = True ...@@ -105,17 +105,24 @@ isInlineStruct (InlineStructType _) = True
isInlineStruct _ = False isInlineStruct _ = False
isList (ListType _) = True isList (ListType _) = True
isList (InlineListType _ _) = True
isList _ = False isList _ = False
isNonStructList (ListType t) = not $ isStruct t isNonStructList (ListType t) = not $ isStruct t
isNonStructList (InlineListType t _) = not $ isStruct t
isNonStructList _ = False isNonStructList _ = False
isPrimitiveList (ListType t) = isPrimitive t isPrimitiveList (ListType t) = isPrimitive t
isPrimitiveList (InlineListType t _) = isPrimitive t
isPrimitiveList _ = False isPrimitiveList _ = False
isStructList (ListType t) = isStruct t isStructList (ListType t) = isStruct t
isStructList (InlineListType t _) = isStruct t
isStructList _ = False isStructList _ = False
isInlineList (InlineListType _ _) = True
isInlineList _ = False
blobTypeString (BuiltinType BuiltinText) = "Text" blobTypeString (BuiltinType BuiltinText) = "Text"
blobTypeString (BuiltinType BuiltinData) = "Data" blobTypeString (BuiltinType BuiltinData) = "Data"
blobTypeString _ = error "Not a blob." blobTypeString _ = error "Not a blob."
...@@ -139,6 +146,7 @@ cxxTypeString (StructType desc) = globalName $ DescStruct desc ...@@ -139,6 +146,7 @@ cxxTypeString (StructType desc) = globalName $ DescStruct desc
cxxTypeString (InlineStructType desc) = globalName $ DescStruct desc cxxTypeString (InlineStructType desc) = globalName $ DescStruct desc
cxxTypeString (InterfaceType desc) = globalName $ DescInterface desc cxxTypeString (InterfaceType desc) = globalName $ DescInterface desc
cxxTypeString (ListType t) = concat [" ::capnproto::List<", cxxTypeString t, ">"] cxxTypeString (ListType t) = concat [" ::capnproto::List<", cxxTypeString t, ">"]
cxxTypeString (InlineListType t _) = concat [" ::capnproto::List<", cxxTypeString t, ">"]
cxxFieldSizeString SizeVoid = "VOID"; cxxFieldSizeString SizeVoid = "VOID";
cxxFieldSizeString (SizeData Size1) = "BIT"; cxxFieldSizeString (SizeData Size1) = "BIT";
...@@ -203,6 +211,7 @@ defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v ...@@ -203,6 +211,7 @@ defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v
defaultValueBytes _ _ = Nothing defaultValueBytes _ _ = Nothing
elementType (ListType t) = t elementType (ListType t) = t
elementType (InlineListType t _) = t
elementType _ = error "Called elementType on non-list." elementType _ = error "Called elementType on non-list."
repeatedlyTake _ [] = [] repeatedlyTake _ [] = []
...@@ -244,6 +253,7 @@ fieldContext parent desc = mkStrContext context where ...@@ -244,6 +253,7 @@ fieldContext parent desc = mkStrContext context where
context "fieldIsNonStructList" = MuBool $ isNonStructList $ fieldType desc context "fieldIsNonStructList" = MuBool $ isNonStructList $ fieldType desc
context "fieldIsPrimitiveList" = MuBool $ isPrimitiveList $ fieldType desc context "fieldIsPrimitiveList" = MuBool $ isPrimitiveList $ fieldType desc
context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc
context "fieldIsInlineList" = MuBool $ isInlineList $ fieldType desc
context "fieldDefaultBytes" = context "fieldDefaultBytes" =
case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of
Just v -> muJust $ defaultBytesContext context (fieldType desc) v Just v -> muJust $ defaultBytesContext context (fieldType desc) v
...@@ -251,6 +261,23 @@ fieldContext parent desc = mkStrContext context where ...@@ -251,6 +261,23 @@ fieldContext parent desc = mkStrContext context where
context "fieldType" = MuVariable $ cxxTypeString $ fieldType desc context "fieldType" = MuVariable $ cxxTypeString $ fieldType desc
context "fieldBlobType" = MuVariable $ blobTypeString $ fieldType desc context "fieldBlobType" = MuVariable $ blobTypeString $ fieldType desc
context "fieldOffset" = MuVariable $ fieldOffsetInteger $ fieldOffset desc context "fieldOffset" = MuVariable $ fieldOffsetInteger $ fieldOffset desc
context "fieldInlineListSize" = case fieldType desc of
InlineListType _ n -> MuVariable n
_ -> muNull
context "fieldInlineDataOffset" = case fieldOffset desc of
InlineCompositeOffset off _ size _ ->
MuVariable (off * dataSizeInBits (dataSectionAlignment size))
_ -> muNull
context "fieldInlineDataSize" = case fieldOffset desc of
InlineCompositeOffset _ _ size _ ->
MuVariable $ dataSectionBits size
_ -> muNull
context "fieldInlinePointerOffset" = case fieldOffset desc of
InlineCompositeOffset _ off _ _ -> MuVariable off
_ -> muNull
context "fieldInlinePointerSize" = case fieldOffset desc of
InlineCompositeOffset _ _ _ size -> MuVariable size
_ -> muNull
context "fieldDefaultMask" = case fieldDefaultValue desc of context "fieldDefaultMask" = case fieldDefaultValue desc of
Nothing -> MuVariable "" Nothing -> MuVariable ""
Just v -> MuVariable (if isDefaultZero v then "" else ", " ++ defaultMask v) Just v -> MuVariable (if isDefaultZero v then "" else ", " ++ defaultMask v)
...@@ -303,6 +330,7 @@ structContext parent desc = mkStrContext context where ...@@ -303,6 +330,7 @@ structContext parent desc = mkStrContext context where
context "structFields" = MuList $ map (fieldContext context) $ structFields desc context "structFields" = MuList $ map (fieldContext context) $ structFields desc
context "structUnions" = MuList $ map (unionContext context) $ structUnions desc context "structUnions" = MuList $ map (unionContext context) $ structUnions desc
context "structDataSize" = MuVariable $ dataSectionWordSize $ structDataSize desc context "structDataSize" = MuVariable $ dataSectionWordSize $ structDataSize desc
context "structDataBits" = MuVariable $ dataSectionBits $ structDataSize desc
context "structReferenceCount" = MuVariable $ structPointerCount desc context "structReferenceCount" = MuVariable $ structPointerCount desc
context "structNestedEnums" = context "structNestedEnums" =
MuList $ map (enumContext context) [m | DescEnum m <- structMembers desc] MuList $ map (enumContext context) [m | DescEnum m <- structMembers desc]
......
...@@ -320,6 +320,7 @@ fieldSize (InterfaceType _) = SizeReference ...@@ -320,6 +320,7 @@ fieldSize (InterfaceType _) = SizeReference
fieldSize (ListType _) = SizeReference fieldSize (ListType _) = SizeReference
fieldSize (InlineListType element size) = let fieldSize (InlineListType element size) = let
minDataSectionForBits bits minDataSectionForBits bits
| bits <= 0 = DataSectionWords 0
| bits <= 1 = DataSection1 | bits <= 1 = DataSection1
| bits <= 8 = DataSection8 | bits <= 8 = DataSection8
| bits <= 16 = DataSection16 | bits <= 16 = DataSection16
...@@ -329,12 +330,12 @@ fieldSize (InlineListType element size) = let ...@@ -329,12 +330,12 @@ fieldSize (InlineListType element size) = let
SizeVoid -> DataSectionWords 0 SizeVoid -> DataSectionWords 0
SizeData s -> minDataSectionForBits $ dataSizeInBits s * size SizeData s -> minDataSectionForBits $ dataSizeInBits s * size
SizeReference -> DataSectionWords 0 SizeReference -> DataSectionWords 0
SizeInlineComposite ds _ -> minDataSectionForBits $ dataSectionBits ds SizeInlineComposite ds _ -> minDataSectionForBits $ dataSectionBits ds * size
pointerCount = case fieldSize element of pointerCount = case fieldSize element of
SizeVoid -> 0 SizeVoid -> 0
SizeData _ -> 0 SizeData _ -> 0
SizeReference -> size SizeReference -> size
SizeInlineComposite _ pc -> pc SizeInlineComposite _ pc -> pc * size
in SizeInlineComposite dataSection pointerCount in SizeInlineComposite dataSection pointerCount
-- Render the type descriptor's name as a string, appropriate for use in the given scope. -- Render the type descriptor's name as a string, appropriate for use in the given scope.
......
...@@ -29,6 +29,7 @@ import Data.Bits(shiftL, shiftR, Bits, setBit, xor) ...@@ -29,6 +29,7 @@ import Data.Bits(shiftL, shiftR, Bits, setBit, xor)
import Data.Function(on) import Data.Function(on)
import Semantics import Semantics
import Data.Binary.IEEE754(floatToWord, doubleToWord) import Data.Binary.IEEE754(floatToWord, doubleToWord)
import Text.Printf(printf)
import qualified Codec.Binary.UTF8.String as UTF8 import qualified Codec.Binary.UTF8.String as UTF8
byte :: (Integral a, Bits a) => a -> Int -> Word8 byte :: (Integral a, Bits a) => a -> Int -> Word8
...@@ -45,6 +46,7 @@ padToWord b = let ...@@ -45,6 +46,7 @@ padToWord b = let
data EncodedData = EncodedBit Bool data EncodedData = EncodedBit Bool
| EncodedBytes [Word8] | EncodedBytes [Word8]
deriving(Show)
xorData (EncodedBit a) (EncodedBit b) = EncodedBit (a /= b) xorData (EncodedBit a) (EncodedBit b) = EncodedBit (a /= b)
xorData (EncodedBytes a) (EncodedBytes b) = EncodedBytes (zipWith xor a b) xorData (EncodedBytes a) (EncodedBytes b) = EncodedBytes (zipWith xor a b)
...@@ -92,7 +94,7 @@ encodePointerValue _ _ = error "Unknown pointer type." ...@@ -92,7 +94,7 @@ encodePointerValue _ _ = error "Unknown pointer type."
packBytes :: Integer -- Total size of array to pack, in bits. packBytes :: Integer -- Total size of array to pack, in bits.
-> [(Integer, EncodedData)] -- (offset, data) pairs to pack. Must be in order. -> [(Integer, EncodedData)] -- (offset, data) pairs to pack. Must be in order.
-> [Word8] -> [Word8]
packBytes size = padToWord . loop 0 where packBytes size items = padToWord $ loop 0 items where
loop :: Integer -> [(Integer, EncodedData)] -> [Word8] loop :: Integer -> [(Integer, EncodedData)] -> [Word8]
loop bit [] | bit <= size = genericReplicate (div (size - bit + 7) 8) 0 loop bit [] | bit <= size = genericReplicate (div (size - bit + 7) 8) 0
loop bit [] | bit > size = error "Data values overran size." loop bit [] | bit > size = error "Data values overran size."
...@@ -103,7 +105,8 @@ packBytes size = padToWord . loop 0 where ...@@ -103,7 +105,8 @@ packBytes size = padToWord . loop 0 where
loop bit ((_, EncodedBit False):rest) = loop bit rest loop bit ((_, EncodedBit False):rest) = loop bit rest
loop bit ((offset, EncodedBytes encoded):rest) | offset == bit = loop bit ((offset, EncodedBytes encoded):rest) | offset == bit =
encoded ++ loop (bit + genericLength encoded * 8) rest encoded ++ loop (bit + genericLength encoded * 8) rest
loop _ _ = error "Data values overlapped." loop bit rest = error
(printf "Data values overlapped @%d: %s\n\n%s" bit (show rest) (show items))
bytesToWords i = if mod i 8 == 0 then div i 8 bytesToWords i = if mod i 8 == 0 then div i 8
else error "Byte count did not divide evenly into words." else error "Byte count did not divide evenly into words."
......
...@@ -69,7 +69,8 @@ struct {{typeFullName}} { ...@@ -69,7 +69,8 @@ struct {{typeFullName}} {
static constexpr ::capnproto::internal::StructSize STRUCT_SIZE = static constexpr ::capnproto::internal::StructSize STRUCT_SIZE =
::capnproto::internal::StructSize({{structDataSize}} * ::capnproto::WORDS, ::capnproto::internal::StructSize({{structDataSize}} * ::capnproto::WORDS,
{{structReferenceCount}} * ::capnproto::REFERENCES); {{structReferenceCount}} * ::capnproto::REFERENCES,
{{structDataBits}} * ::capnproto::BITS);
{{/typeStruct}} {{/typeStruct}}
{{#typeUnion}} {{#typeUnion}}
...@@ -172,7 +173,12 @@ public: ...@@ -172,7 +173,12 @@ public:
inline {{fieldType}}::Builder get{{fieldTitleCase}}(); inline {{fieldType}}::Builder get{{fieldTitleCase}}();
{{/fieldIsStruct}} {{/fieldIsStruct}}
{{#fieldIsNonStructList}} {{#fieldIsNonStructList}}
{{#fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}();
{{/fieldIsInlineList}}
{{^fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size); inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsInlineList}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}(); inline {{fieldType}}::Builder get{{fieldTitleCase}}();
template <typename _t> template <typename _t>
inline void set{{fieldTitleCase}}(const _t& other); inline void set{{fieldTitleCase}}(const _t& other);
...@@ -184,7 +190,12 @@ public: ...@@ -184,7 +190,12 @@ public:
{{/fieldIsPrimitiveList}} {{/fieldIsPrimitiveList}}
{{/fieldIsNonStructList}} {{/fieldIsNonStructList}}
{{#fieldIsStructList}} {{#fieldIsStructList}}
{{#fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}();
{{/fieldIsInlineList}}
{{^fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size); inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsInlineList}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}(); inline {{fieldType}}::Builder get{{fieldTitleCase}}();
{{/fieldIsStructList}} {{/fieldIsStructList}}
{{/typeFields}} {{/typeFields}}
...@@ -356,6 +367,75 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() ...@@ -356,6 +367,75 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{/fieldIsStruct}} {{/fieldIsStruct}}
{{! ------------------------------------------------------------------------------------------- }} {{! ------------------------------------------------------------------------------------------- }}
{{#fieldIsNonStructList}} {{#fieldIsNonStructList}}
{{#fieldIsInlineList}}
{{#fieldIsPrimitiveList}}
inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Reader(_reader.getInlineDataListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
::capnproto::internal::FieldSize::{{fieldElementSize}}));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}() {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.initInlineDataListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlineDataSize}} * ::capnproto::BITS,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
::capnproto::internal::FieldSize::{{fieldElementSize}}));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.getInlineDataListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
::capnproto::internal::FieldSize::{{fieldElementSize}}));
}
{{/fieldIsPrimitiveList}}
{{^fieldIsPrimitiveList}}
inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Reader(_reader.getInlinePointerListField(
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}() {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.initInlinePointerListField(
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlinePointerSize}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.getInlinePointerListField(
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS));
}
{{/fieldIsPrimitiveList}}
{{/fieldIsInlineList}}
{{! --------------------------------- }}
{{^fieldIsInlineList}}
inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() { inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() {
{{#fieldUnion}} {{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}}, CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
...@@ -388,15 +468,17 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() ...@@ -388,15 +468,17 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}} {{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}})); {{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
} }
{{/fieldIsInlineList}}
{{! --------------------------------- }}
template <typename _t> template <typename _t>
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(const _t& other) { inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(const _t& other) {
{{#fieldUnion}} {{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>( _builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}}); {{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}} {{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other); init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
} }
{{! ------------------------------------------------------------------------------------------- }}
{{#fieldIsPrimitiveList}} {{#fieldIsPrimitiveList}}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementType}}> other) { std::initializer_list<{{fieldElementType}}> other) {
...@@ -404,10 +486,9 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( ...@@ -404,10 +486,9 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
_builder.setDataField<{{unionTitleCase}}::Which>( _builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}}); {{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}} {{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other); init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
} }
{{/fieldIsPrimitiveList}} {{/fieldIsPrimitiveList}}
{{! ------------------------------------------------------------------------------------------- }}
{{^fieldIsPrimitiveList}} {{^fieldIsPrimitiveList}}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementType}}::Reader> other) { std::initializer_list<{{fieldElementType}}::Reader> other) {
...@@ -415,12 +496,49 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( ...@@ -415,12 +496,49 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
_builder.setDataField<{{unionTitleCase}}::Which>( _builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}}); {{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}} {{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other); init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
} }
{{/fieldIsPrimitiveList}} {{/fieldIsPrimitiveList}}
{{/fieldIsNonStructList}} {{/fieldIsNonStructList}}
{{! ------------------------------------------------------------------------------------------- }} {{! ------------------------------------------------------------------------------------------- }}
{{#fieldIsStructList}} {{#fieldIsStructList}}
{{#fieldIsInlineList}}
inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Reader(_reader.getInlineStructListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
{{fieldElementType}}::STRUCT_SIZE));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}() {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.initInlineStructListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
{{fieldElementType}}::STRUCT_SIZE));
}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return {{fieldType}}::Builder(_builder.getInlineStructListField(
{{fieldInlineDataOffset}} * ::capnproto::BITS,
{{fieldInlinePointerOffset}} * ::capnproto::REFERENCES,
{{fieldInlineListSize}} * ::capnproto::ELEMENTS,
{{fieldElementType}}::STRUCT_SIZE));
}
{{/fieldIsInlineList}}
{{^fieldIsInlineList}}
inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() { inline {{fieldType}}::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}() {
{{#fieldUnion}} {{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}}, CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
...@@ -452,6 +570,7 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}() ...@@ -452,6 +570,7 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}} {{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}})); {{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
} }
{{/fieldIsInlineList}}
{{/fieldIsStructList}} {{/fieldIsStructList}}
{{/typeFields}} {{/typeFields}}
{{/typeStructOrUnion}} {{/typeStructOrUnion}}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment