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) {
EXPECT_EQ("qux", unions.getUnion3().getF16p().getP0());
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,
static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT =
{{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) {
builder.setDataField<uint64_t>(0 * ELEMENTS, 0x1011121314151617ull);
builder.setDataField<uint32_t>(2 * ELEMENTS, 0x20212223u);
......@@ -118,7 +120,7 @@ static void setupStruct(StructBuilder builder) {
{
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);
}
......@@ -132,12 +134,12 @@ static void setupStruct(StructBuilder builder) {
{
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());
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.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);
}
}
......@@ -147,7 +149,7 @@ static void setupStruct(StructBuilder builder) {
EXPECT_EQ(5 * ELEMENTS, list.size());
for (uint i = 0; i < 5; i++) {
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());
for (uint j = 0; j <= i; j++) {
element.setDataElement<uint16_t>(j * ELEMENTS, 500 + j);
......@@ -172,7 +174,7 @@ static void checkStruct(StructBuilder builder) {
{
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));
}
......@@ -188,10 +190,10 @@ static void checkStruct(StructBuilder builder) {
ListBuilder list = builder.getListField(2 * REFERENCES, nullptr);
ASSERT_EQ(4 * ELEMENTS, list.size());
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(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)
.getDataField<int32_t>(0 * ELEMENTS));
}
......@@ -201,7 +203,7 @@ static void checkStruct(StructBuilder builder) {
ListBuilder list = builder.getListField(3 * REFERENCES, nullptr);
ASSERT_EQ(5 * ELEMENTS, list.size());
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());
for (uint j = 0; j <= i; j++) {
EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS));
......@@ -254,7 +256,7 @@ static void checkStruct(StructReader reader) {
ListReader list = reader.getListField(3 * REFERENCES, FieldSize::REFERENCE, nullptr);
ASSERT_EQ(5 * ELEMENTS, list.size());
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());
for (uint j = 0; j <= i; j++) {
EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS));
......@@ -270,7 +272,7 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder);
// word count:
......@@ -306,7 +308,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder);
// Verify that we made 15 segments.
......@@ -343,7 +345,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 128 * BITS));
setupStruct(builder);
// Verify that we made 6 segments.
......
......@@ -415,7 +415,8 @@ struct WireHelpers {
ref->structRef.set(size);
// 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(
......@@ -442,7 +443,8 @@ struct WireHelpers {
"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(
......@@ -451,9 +453,10 @@ struct WireHelpers {
DPRECOND(elementSize != FieldSize::INLINE_COMPOSITE,
"Should have called initStructListReference() instead.");
auto step = bitsPerElement(elementSize);
// Calculate size of the list.
WordCount wordCount = roundUpToWords(
ElementCount64(elementCount) * bitsPerElement(elementSize));
WordCount wordCount = roundUpToWords(ElementCount64(elementCount) * step);
// Allocate the list.
word* ptr = allocate(ref, segment, wordCount, WireReference::LIST);
......@@ -462,12 +465,33 @@ struct WireHelpers {
ref->listRef.set(elementSize, elementCount);
// 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(
WireReference* ref, SegmentBuilder* segment, ElementCount elementCount,
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;
// Allocate the list, prefixed by a single WireReference.
......@@ -485,7 +509,9 @@ struct WireHelpers {
ptr += REFERENCE_SIZE_IN_WORDS;
// 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(
......@@ -495,7 +521,8 @@ struct WireHelpers {
if (ref->isNull()) {
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);
} else {
......@@ -510,12 +537,19 @@ struct WireHelpers {
WireReference* tag = reinterpret_cast<WireReference*>(ptr);
PRECOND(tag->kind() == WireReference::STRUCT,
"INLINE_COMPOSITE list with non-STRUCT elements not supported.");
ElementCount elementCount = tag->inlineCompositeListElementCount();
// 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 {
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 {
if (ref == nullptr || ref->isNull()) {
useDefault:
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;
ref = reinterpret_cast<const WireReference*>(defaultValue);
......@@ -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.refCount.get(), nestingLimit - 1);
......@@ -768,7 +807,9 @@ struct WireHelpers {
}
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) {
// 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
......@@ -792,7 +833,8 @@ struct WireHelpers {
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);
} else {
PRECOND(segment != nullptr, "Trusted message had incompatible list element type.");
......@@ -1017,101 +1059,102 @@ Data::Reader StructReader::getDataField(
return WireHelpers::readDataReference(segment, ref, defaultValue, defaultSize);
}
StructBuilder ListBuilder::getStructElement(
ElementCount index, decltype(WORDS/ELEMENTS) elementSize, WordCount structDataSize) const {
word* structPtr = ptr + elementSize * index;
return StructBuilder(segment, structPtr,
reinterpret_cast<WireReference*>(structPtr + structDataSize), 0 * BITS);
StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const {
// TODO: Inline this method?
BitCount64 indexBit = ElementCount64(index) * stepBits;
byte* structData = reinterpret_cast<byte*>(data) + indexBit / BITS_PER_BYTE;
WireReference* structPointers = pointers + index * stepPointers;
return StructBuilder(segment, structData, structPointers, indexBit % BITS_PER_BYTE,
elementSize.pointers);
}
ListBuilder ListBuilder::initListElement(
WireReferenceCount index, FieldSize elementSize, ElementCount elementCount) const {
ElementCount index, FieldSize elementSize, ElementCount elementCount) const {
return WireHelpers::initListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment,
pointers + index * stepPointers, segment,
elementCount, elementSize);
}
ListBuilder ListBuilder::initStructListElement(
WireReferenceCount index, ElementCount elementCount, StructSize elementSize) const {
ElementCount index, ElementCount elementCount, StructSize elementSize) const {
return WireHelpers::initStructListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment,
pointers + index * stepPointers, segment,
elementCount, elementSize);
}
ListBuilder ListBuilder::getListElement(WireReferenceCount index) const {
ListBuilder ListBuilder::getListElement(ElementCount index) const {
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(
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(
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(
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(
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(
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(
reinterpret_cast<WireReference*>(ptr) + index, segment, nullptr, 0 * BYTES);
pointers + index * stepPointers, segment, nullptr, 0 * BYTES);
}
ListReader ListBuilder::asReader(FieldSize elementSize) const {
// TODO: For INLINE_COMPOSITE I suppose we could just check the tag?
PRECOND(elementSize != FieldSize::INLINE_COMPOSITE,
"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());
}
ListReader ListBuilder::asReader(BitCount dataSize, WireReferenceCount referenceCount) const {
return ListReader(segment, ptr, elementCount,
(dataSize + referenceCount * WORDS_PER_REFERENCE * BITS_PER_WORD) / ELEMENTS,
dataSize, referenceCount, std::numeric_limits<int>::max());
ListReader ListBuilder::asReader(StructSize elementSize) const {
return ListReader(segment, data, pointers, elementCount, stepBits, stepPointers,
elementSize.dataBits, elementSize.pointers, std::numeric_limits<int>::max());
}
StructReader ListReader::getStructElement(ElementCount index) const {
// TODO: Inline this method?
VALIDATE_INPUT((segment == nullptr) | (nestingLimit > 0),
"Message is too deeply-nested or contains cycles. See capnproto::ReadOptions.") {
return StructReader::readEmpty();
}
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(
segment, structPtr,
reinterpret_cast<const WireReference*>(structPtr + structDataSize / BITS_PER_BYTE),
segment, structData, pointers + index * stepPointers,
structDataSize, structReferenceCount, indexBit % BITS_PER_BYTE, nestingLimit - 1);
}
ListReader ListReader::getListElement(
WireReferenceCount index, FieldSize expectedElementSize) const {
ElementCount index, FieldSize expectedElementSize) const {
return WireHelpers::readListReference(
segment, reinterpret_cast<const WireReference*>(ptr) + index,
segment, pointers + index * stepPointers,
nullptr, expectedElementSize, nestingLimit);
}
Text::Reader ListReader::getTextElement(WireReferenceCount index) const {
return WireHelpers::readTextReference(segment,
reinterpret_cast<const WireReference*>(ptr) + index, "", 0 * BYTES);
Text::Reader ListReader::getTextElement(ElementCount index) const {
return WireHelpers::readTextReference(
segment, pointers + index * stepPointers, "", 0 * BYTES);
}
Data::Reader ListReader::getDataElement(WireReferenceCount index) const {
return WireHelpers::readDataReference(segment,
reinterpret_cast<const WireReference*>(ptr) + index, nullptr, 0 * BYTES);
Data::Reader ListReader::getDataElement(ElementCount index) const {
return WireHelpers::readDataReference(
segment, pointers + index * stepPointers, nullptr, 0 * BYTES);
}
} // namespace internal
......
......@@ -132,11 +132,15 @@ struct StructSize {
WordCount16 data;
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; }
StructSize() = default;
inline constexpr StructSize(WordCount data, WireReferenceCount pointers)
: data(data), pointers(pointers) {}
inline constexpr StructSize(WordCount data, WireReferenceCount pointers, BitCount dataBits)
: data(data), pointers(pointers), dataBits(dataBits) {}
};
template <typename T>
......@@ -307,6 +311,34 @@ public:
// 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.
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;
// 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.
......@@ -327,6 +359,8 @@ public:
StructReader asReader() const;
// Gets a StructReader pointing at the same memory.
WireReferenceCount getReferenceCount() { return referenceCount; }
private:
SegmentBuilder* segment; // Memory segment in which the struct resides.
void* data; // Pointer to the encoded data.
......@@ -336,9 +370,13 @@ private:
// 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.
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,
BitCount8 bit0Offset)
: segment(segment), data(data), references(references), bit0Offset(bit0Offset) {}
BitCount8 bit0Offset, WireReferenceCount referenceCount)
: segment(segment), data(data), references(references), bit0Offset(bit0Offset),
referenceCount(referenceCount) {}
friend class ListBuilder;
friend struct WireHelpers;
......@@ -382,6 +420,19 @@ public:
// 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.
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,
const void* defaultValue, ByteCount defaultSize) const;
// Gets the text field, or the given default value if not initialized.
......@@ -390,6 +441,8 @@ public:
const void* defaultValue, ByteCount defaultSize) const;
// Gets the data field, or the given default value if not initialized.
WireReferenceCount getReferenceCount() { return referenceCount; }
private:
SegmentReader* segment; // Memory segment in which the struct resides.
......@@ -425,7 +478,9 @@ private:
class ListBuilder {
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();
// The number of elements in the list.
......@@ -439,52 +494,61 @@ public:
ElementCount index, typename NoInfer<T>::Type value) const);
// Set the element at the given index.
StructBuilder getStructElement(
ElementCount index, decltype(WORDS/ELEMENTS) elementSize, WordCount structDataSize) const;
// Get the struct element at the given index. elementSize is the size, in 64-bit words, of
// each element.
StructBuilder getStructElement(ElementCount index, StructSize elementSize) const;
// Get the struct element at the given index.
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
// to zero.
ListBuilder initStructListElement(WireReferenceCount index, ElementCount elementCount,
ListBuilder initStructListElement(ElementCount index, ElementCount elementCount,
StructSize size) const;
// 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.
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
// 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
// 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.
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.
Data::Builder initDataElement(WireReferenceCount index, ByteCount size) const;
void setDataElement(WireReferenceCount index, Data::Reader value) const;
Data::Builder getDataElement(WireReferenceCount index) const;
Data::Builder initDataElement(ElementCount index, ByteCount size) const;
void setDataElement(ElementCount index, Data::Reader value) const;
Data::Builder getDataElement(ElementCount index) const;
ListReader asReader(FieldSize elementSize) const;
// 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.
private:
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.
inline ListBuilder(SegmentBuilder* segment, word* ptr, ElementCount size)
: segment(segment), ptr(ptr), elementCount(size) {}
decltype(BITS / ELEMENTS) stepBits;
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 struct WireHelpers;
......@@ -493,9 +557,9 @@ private:
class ListReader {
public:
inline ListReader()
: segment(nullptr), ptr(nullptr), elementCount(0),
stepBits(0 * BITS / ELEMENTS), structDataSize(0),
structReferenceCount(0), nestingLimit(0) {}
: segment(nullptr), data(nullptr), pointers(nullptr), elementCount(0),
stepBits(0 * BITS / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS),
structDataSize(0), structReferenceCount(0), nestingLimit(0) {}
inline ElementCount size();
// The number of elements in the list.
......@@ -507,50 +571,49 @@ public:
StructReader getStructElement(ElementCount index) const;
// 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.
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.
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.
private:
SegmentReader* segment; // Memory segment in which the list resides.
const void* ptr;
// Pointer to the data. If null, use defaultReferences. (Never null for data lists.)
// Must be aligned appropriately for the elements.
const void* data;
const WireReference* pointers;
// Pointers to list content.
ElementCount elementCount; // Number of elements in the list.
decltype(BITS / ELEMENTS) stepBits;
// The distance between elements, in bits. This is usually the element size, but can be larger
// if the sender upgraded a data list to a struct list. It will always be aligned properly for
// the type. Unsigned so that division by a constant power of 2 is efficient.
decltype(REFERENCES / ELEMENTS) stepPointers;
// The distance between elements. Can be tricky e.g. for inlined struct lists.
BitCount structDataSize;
WireReferenceCount structReferenceCount;
// If the elements are structs, the properties of the struct. The reference count is
// only used to check for field presence; the data size is also used to compute the reference
// pointer.
// If the elements are structs, the properties of the struct.
int nestingLimit;
// Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
// Once this reaches zero, further pointers will be pruned.
inline ListReader(SegmentReader* segment, const void* ptr, ElementCount elementCount,
decltype(BITS / ELEMENTS) stepBits, int nestingLimit)
: segment(segment), ptr(ptr), elementCount(elementCount), stepBits(stepBits),
structDataSize(0), structReferenceCount(0),
inline ListReader(SegmentReader* segment, const void* data, const WireReference* pointers,
ElementCount elementCount, decltype(BITS / ELEMENTS) stepBits,
decltype(REFERENCES / ELEMENTS) stepPointers, int nestingLimit)
: segment(segment), data(data), pointers(pointers), elementCount(elementCount),
stepBits(stepBits), stepPointers(stepPointers), structDataSize(0), structReferenceCount(0),
nestingLimit(nestingLimit) {}
inline ListReader(SegmentReader* segment, const void* ptr, ElementCount elementCount,
decltype(BITS / ELEMENTS) stepBits, BitCount structDataSize,
inline ListReader(SegmentReader* segment, const void* data, const WireReference* pointers,
ElementCount elementCount, decltype(BITS / ELEMENTS) stepBits,
decltype(REFERENCES / ELEMENTS) stepPointers, BitCount structDataSize,
WireReferenceCount structReferenceCount, int nestingLimit)
: segment(segment), ptr(ptr), elementCount(elementCount), stepBits(stepBits),
structDataSize(structDataSize), structReferenceCount(structReferenceCount),
nestingLimit(nestingLimit) {}
: segment(segment), data(data), pointers(pointers), elementCount(elementCount),
stepBits(stepBits), stepPointers(stepPointers), structDataSize(structDataSize),
structReferenceCount(structReferenceCount), nestingLimit(nestingLimit) {}
friend class StructReader;
friend class ListBuilder;
......@@ -637,14 +700,68 @@ inline StructBuilder StructBuilder::getInlineStructField(
// WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast<WireReference*>(
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>
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();
} else {
return static_cast<T>(0);
......@@ -689,19 +806,49 @@ inline StructReader StructReader::getInlineStructField(
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; }
template <typename T>
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 <>
inline bool ListBuilder::getDataElement<bool>(ElementCount index) const {
BitCount bindex = index * (1 * BITS / ELEMENTS);
byte* b = reinterpret_cast<byte*>(ptr) + bindex / BITS_PER_BYTE;
BitCount bindex = index * stepBits;
byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
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 {
template <typename T>
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 <>
inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) const {
BitCount bindex = index * (1 * BITS / ELEMENTS);
byte* b = reinterpret_cast<byte*>(ptr) + bindex / BITS_PER_BYTE;
BitCount bindex = index * stepBits;
byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
uint bitnum = bindex % BITS_PER_BYTE / BITS;
*reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum))
| (static_cast<uint8_t>(value) << bitnum);
......@@ -733,14 +881,14 @@ inline ElementCount ListReader::size() { return elementCount; }
template <typename T>
inline T ListReader::getDataElement(ElementCount index) const {
return *reinterpret_cast<const T*>(
reinterpret_cast<const byte*>(ptr) + index * stepBits / BITS_PER_BYTE);
return reinterpret_cast<const WireValue<T>*>(
reinterpret_cast<const byte*>(data) + index * stepBits / BITS_PER_BYTE)->get();
}
template <>
inline bool ListReader::getDataElement<bool>(ElementCount index) const {
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;
}
......
......@@ -236,8 +236,7 @@ struct List<T, false> {
inline uint size() { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) {
return typename T::Builder(builder.getStructElement(index * ELEMENTS,
T::STRUCT_SIZE.total() / ELEMENTS, T::STRUCT_SIZE.data));
return typename T::Builder(builder.getStructElement(index * ELEMENTS, T::STRUCT_SIZE));
}
typedef internal::IndexingIterator<Builder, typename T::Builder> iterator;
......@@ -282,11 +281,11 @@ struct List<List<T>, true> {
inline uint size() { return builder.size() / ELEMENTS; }
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) {
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;
......@@ -312,7 +311,7 @@ struct List<List<T>, false> {
inline uint size() { return reader.size() / ELEMENTS; }
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));
}
......@@ -331,11 +330,11 @@ struct List<List<T>, false> {
inline uint size() { return builder.size() / ELEMENTS; }
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) {
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;
......@@ -361,7 +360,7 @@ struct List<Data, false> {
inline uint size() { return reader.size() / ELEMENTS; }
inline Data::Reader operator[](uint index) {
return reader.getDataElement(index * REFERENCES);
return reader.getDataElement(index * ELEMENTS);
}
typedef internal::IndexingIterator<Reader, Data::Reader> iterator;
......@@ -379,13 +378,13 @@ struct List<Data, false> {
inline uint size() { return builder.size() / ELEMENTS; }
inline Data::Builder operator[](uint index) {
return builder.getDataElement(index * REFERENCES);
return builder.getDataElement(index * ELEMENTS);
}
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) {
return builder.initDataElement(index * REFERENCES, size * BYTES);
return builder.initDataElement(index * ELEMENTS, size * BYTES);
}
typedef internal::IndexingIterator<Builder, Data::Builder> iterator;
......@@ -425,7 +424,7 @@ struct List<Text, false> {
inline uint size() { return reader.size() / ELEMENTS; }
inline Text::Reader operator[](uint index) {
return reader.getTextElement(index * REFERENCES);
return reader.getTextElement(index * ELEMENTS);
}
typedef internal::IndexingIterator<Reader, Text::Reader> iterator;
......@@ -443,13 +442,13 @@ struct List<Text, false> {
inline uint size() { return builder.size() / ELEMENTS; }
inline Text::Builder operator[](uint index) {
return builder.getTextElement(index * REFERENCES);
return builder.getTextElement(index * ELEMENTS);
}
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) {
return builder.initTextElement(index * REFERENCES, size * BYTES);
return builder.initTextElement(index * ELEMENTS, size * BYTES);
}
typedef internal::IndexingIterator<Builder, Text::Builder> iterator;
......
......@@ -276,7 +276,7 @@ struct TestUsing {
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 TestInline8 fixed(8 bits) { f0 @0: Bool; f1 @1: Bool; f2 @2: Bool; }
struct TestInline16 fixed(16 bits) { f0 @0: UInt8; f1 @1: UInt8; }
......@@ -384,9 +384,37 @@ struct TestInlineUnions {
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 {
normal @0 :TestInlineLayout = (
f0 = (),
f0 = (f = void),
f1 = (f = true),
f8 = (f0 = true, f1 = false, f2 = true),
f16 = (f0 = 123, f1 = 45),
......@@ -411,4 +439,52 @@ struct TestInlineDefaults {
union1 = f128(f0 = 1234567890123, f1 = 4567890123456),
union2 = f1p(p0 = "foo"),
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:
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:
Number unit1PerUnit2;
......
......@@ -295,7 +295,13 @@ compileType scope (TypeExpression n params) = do
desc <- lookupDesc scope n
case desc 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."
DescBuiltinInline -> case params of
[TypeParameterType param] -> do
......@@ -311,7 +317,18 @@ compileType scope (TypeExpression n params) = do
DescBuiltinInlineList -> case params of
[TypeParameterType param, TypeParameterInteger size] -> do
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)
"'InlineList' requires exactly two type parameters: a type and a size."
_ -> case params of
......
......@@ -105,17 +105,24 @@ isInlineStruct (InlineStructType _) = True
isInlineStruct _ = False
isList (ListType _) = True
isList (InlineListType _ _) = True
isList _ = False
isNonStructList (ListType t) = not $ isStruct t
isNonStructList (InlineListType t _) = not $ isStruct t
isNonStructList _ = False
isPrimitiveList (ListType t) = isPrimitive t
isPrimitiveList (InlineListType t _) = isPrimitive t
isPrimitiveList _ = False
isStructList (ListType t) = isStruct t
isStructList (InlineListType t _) = isStruct t
isStructList _ = False
isInlineList (InlineListType _ _) = True
isInlineList _ = False
blobTypeString (BuiltinType BuiltinText) = "Text"
blobTypeString (BuiltinType BuiltinData) = "Data"
blobTypeString _ = error "Not a blob."
......@@ -139,6 +146,7 @@ cxxTypeString (StructType desc) = globalName $ DescStruct desc
cxxTypeString (InlineStructType desc) = globalName $ DescStruct desc
cxxTypeString (InterfaceType desc) = globalName $ DescInterface desc
cxxTypeString (ListType t) = concat [" ::capnproto::List<", cxxTypeString t, ">"]
cxxTypeString (InlineListType t _) = concat [" ::capnproto::List<", cxxTypeString t, ">"]
cxxFieldSizeString SizeVoid = "VOID";
cxxFieldSizeString (SizeData Size1) = "BIT";
......@@ -203,6 +211,7 @@ defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v
defaultValueBytes _ _ = Nothing
elementType (ListType t) = t
elementType (InlineListType t _) = t
elementType _ = error "Called elementType on non-list."
repeatedlyTake _ [] = []
......@@ -244,6 +253,7 @@ fieldContext parent desc = mkStrContext context where
context "fieldIsNonStructList" = MuBool $ isNonStructList $ fieldType desc
context "fieldIsPrimitiveList" = MuBool $ isPrimitiveList $ fieldType desc
context "fieldIsStructList" = MuBool $ isStructList $ fieldType desc
context "fieldIsInlineList" = MuBool $ isInlineList $ fieldType desc
context "fieldDefaultBytes" =
case fieldDefaultValue desc >>= defaultValueBytes (fieldType desc) of
Just v -> muJust $ defaultBytesContext context (fieldType desc) v
......@@ -251,6 +261,23 @@ fieldContext parent desc = mkStrContext context where
context "fieldType" = MuVariable $ cxxTypeString $ fieldType desc
context "fieldBlobType" = MuVariable $ blobTypeString $ fieldType 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
Nothing -> MuVariable ""
Just v -> MuVariable (if isDefaultZero v then "" else ", " ++ defaultMask v)
......@@ -303,6 +330,7 @@ structContext parent desc = mkStrContext context where
context "structFields" = MuList $ map (fieldContext context) $ structFields desc
context "structUnions" = MuList $ map (unionContext context) $ structUnions desc
context "structDataSize" = MuVariable $ dataSectionWordSize $ structDataSize desc
context "structDataBits" = MuVariable $ dataSectionBits $ structDataSize desc
context "structReferenceCount" = MuVariable $ structPointerCount desc
context "structNestedEnums" =
MuList $ map (enumContext context) [m | DescEnum m <- structMembers desc]
......
......@@ -320,6 +320,7 @@ fieldSize (InterfaceType _) = SizeReference
fieldSize (ListType _) = SizeReference
fieldSize (InlineListType element size) = let
minDataSectionForBits bits
| bits <= 0 = DataSectionWords 0
| bits <= 1 = DataSection1
| bits <= 8 = DataSection8
| bits <= 16 = DataSection16
......@@ -329,12 +330,12 @@ fieldSize (InlineListType element size) = let
SizeVoid -> DataSectionWords 0
SizeData s -> minDataSectionForBits $ dataSizeInBits s * size
SizeReference -> DataSectionWords 0
SizeInlineComposite ds _ -> minDataSectionForBits $ dataSectionBits ds
SizeInlineComposite ds _ -> minDataSectionForBits $ dataSectionBits ds * size
pointerCount = case fieldSize element of
SizeVoid -> 0
SizeData _ -> 0
SizeReference -> size
SizeInlineComposite _ pc -> pc
SizeInlineComposite _ pc -> pc * size
in SizeInlineComposite dataSection pointerCount
-- 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)
import Data.Function(on)
import Semantics
import Data.Binary.IEEE754(floatToWord, doubleToWord)
import Text.Printf(printf)
import qualified Codec.Binary.UTF8.String as UTF8
byte :: (Integral a, Bits a) => a -> Int -> Word8
......@@ -45,6 +46,7 @@ padToWord b = let
data EncodedData = EncodedBit Bool
| EncodedBytes [Word8]
deriving(Show)
xorData (EncodedBit a) (EncodedBit b) = EncodedBit (a /= b)
xorData (EncodedBytes a) (EncodedBytes b) = EncodedBytes (zipWith xor a b)
......@@ -92,7 +94,7 @@ encodePointerValue _ _ = error "Unknown pointer type."
packBytes :: Integer -- Total size of array to pack, in bits.
-> [(Integer, EncodedData)] -- (offset, data) pairs to pack. Must be in order.
-> [Word8]
packBytes size = padToWord . loop 0 where
packBytes size items = padToWord $ loop 0 items where
loop :: Integer -> [(Integer, EncodedData)] -> [Word8]
loop bit [] | bit <= size = genericReplicate (div (size - bit + 7) 8) 0
loop bit [] | bit > size = error "Data values overran size."
......@@ -103,7 +105,8 @@ packBytes size = padToWord . loop 0 where
loop bit ((_, EncodedBit False):rest) = loop bit rest
loop bit ((offset, EncodedBytes encoded):rest) | offset == bit =
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
else error "Byte count did not divide evenly into words."
......
......@@ -69,7 +69,8 @@ struct {{typeFullName}} {
static constexpr ::capnproto::internal::StructSize STRUCT_SIZE =
::capnproto::internal::StructSize({{structDataSize}} * ::capnproto::WORDS,
{{structReferenceCount}} * ::capnproto::REFERENCES);
{{structReferenceCount}} * ::capnproto::REFERENCES,
{{structDataBits}} * ::capnproto::BITS);
{{/typeStruct}}
{{#typeUnion}}
......@@ -172,7 +173,12 @@ public:
inline {{fieldType}}::Builder get{{fieldTitleCase}}();
{{/fieldIsStruct}}
{{#fieldIsNonStructList}}
{{#fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}();
{{/fieldIsInlineList}}
{{^fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsInlineList}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}();
template <typename _t>
inline void set{{fieldTitleCase}}(const _t& other);
......@@ -184,7 +190,12 @@ public:
{{/fieldIsPrimitiveList}}
{{/fieldIsNonStructList}}
{{#fieldIsStructList}}
{{#fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}();
{{/fieldIsInlineList}}
{{^fieldIsInlineList}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsInlineList}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}();
{{/fieldIsStructList}}
{{/typeFields}}
......@@ -356,6 +367,75 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{/fieldIsStruct}}
{{! ------------------------------------------------------------------------------------------- }}
{{#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}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
......@@ -388,15 +468,17 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
}
{{/fieldIsInlineList}}
{{! --------------------------------- }}
template <typename _t>
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(const _t& other) {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other);
init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
}
{{! ------------------------------------------------------------------------------------------- }}
{{#fieldIsPrimitiveList}}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementType}}> other) {
......@@ -404,10 +486,9 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other);
init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
}
{{/fieldIsPrimitiveList}}
{{! ------------------------------------------------------------------------------------------- }}
{{^fieldIsPrimitiveList}}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementType}}::Reader> other) {
......@@ -415,12 +496,49 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
init{{fieldTitleCase}}(other.size()).copyFrom(other);
init{{fieldTitleCase}}({{^fieldIsInlineList}}other.size(){{/fieldIsInlineList}}).copyFrom(other);
}
{{/fieldIsPrimitiveList}}
{{/fieldIsNonStructList}}
{{! ------------------------------------------------------------------------------------------- }}
{{#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}}() {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
......@@ -452,6 +570,7 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
}
{{/fieldIsInlineList}}
{{/fieldIsStructList}}
{{/typeFields}}
{{/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