Commit f966fc41 authored by Kenton Varda's avatar Kenton Varda

Store primitive fields XOR'd with their defaults.

parent f3c4121b
...@@ -45,46 +45,58 @@ TEST(WireFormat, SimpleRawDataStruct) { ...@@ -45,46 +45,58 @@ TEST(WireFormat, SimpleRawDataStruct) {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
}}; }};
StructReader reader = StructReader::readRootTrusted(data.words, data.words); StructReader reader = StructReader::readRootTrusted(data.words);
EXPECT_EQ(0xefcdab8967452301ull, reader.getDataField<uint64_t>(0 * ELEMENTS, 321u)); EXPECT_EQ(0xefcdab8967452301ull, reader.getDataField<uint64_t>(0 * ELEMENTS));
EXPECT_EQ(0u, reader.getDataField<uint64_t>(1 * ELEMENTS));
EXPECT_EQ(0x67452301u, reader.getDataField<uint32_t>(0 * ELEMENTS));
EXPECT_EQ(0xefcdab89u, reader.getDataField<uint32_t>(1 * ELEMENTS));
EXPECT_EQ(0u, reader.getDataField<uint32_t>(2 * ELEMENTS));
EXPECT_EQ(0x2301u, reader.getDataField<uint16_t>(0 * ELEMENTS));
EXPECT_EQ(0x6745u, reader.getDataField<uint16_t>(1 * ELEMENTS));
EXPECT_EQ(0xab89u, reader.getDataField<uint16_t>(2 * ELEMENTS));
EXPECT_EQ(0xefcdu, reader.getDataField<uint16_t>(3 * ELEMENTS));
EXPECT_EQ(0u, reader.getDataField<uint16_t>(4 * ELEMENTS));
EXPECT_EQ(321u ^ 0xefcdab8967452301ull, reader.getDataField<uint64_t>(0 * ELEMENTS, 321u));
EXPECT_EQ(321u ^ 0x67452301u, reader.getDataField<uint32_t>(0 * ELEMENTS, 321u));
EXPECT_EQ(321u ^ 0x2301u, reader.getDataField<uint16_t>(0 * ELEMENTS, 321u));
EXPECT_EQ(321u, reader.getDataField<uint64_t>(1 * ELEMENTS, 321u)); EXPECT_EQ(321u, reader.getDataField<uint64_t>(1 * ELEMENTS, 321u));
EXPECT_EQ(0x67452301u, reader.getDataField<uint32_t>(0 * ELEMENTS, 321u));
EXPECT_EQ(0xefcdab89u, reader.getDataField<uint32_t>(1 * ELEMENTS, 321u));
EXPECT_EQ(321u, reader.getDataField<uint32_t>(2 * ELEMENTS, 321u)); EXPECT_EQ(321u, reader.getDataField<uint32_t>(2 * ELEMENTS, 321u));
EXPECT_EQ(0x2301u, reader.getDataField<uint16_t>(0 * ELEMENTS, 321u));
EXPECT_EQ(0x6745u, reader.getDataField<uint16_t>(1 * ELEMENTS, 321u));
EXPECT_EQ(0xab89u, reader.getDataField<uint16_t>(2 * ELEMENTS, 321u));
EXPECT_EQ(0xefcdu, reader.getDataField<uint16_t>(3 * ELEMENTS, 321u));
EXPECT_EQ(321u, reader.getDataField<uint16_t>(4 * ELEMENTS, 321u)); EXPECT_EQ(321u, reader.getDataField<uint16_t>(4 * ELEMENTS, 321u));
// Bits // Bits
EXPECT_TRUE (reader.getDataField<bool>(0 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(1 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(2 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(3 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(4 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(5 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(6 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(7 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>( 8 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>( 9 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(10 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(11 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(12 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(13 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(14 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(15 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(64 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(0 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(0 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(1 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(1 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(2 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(3 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(4 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(5 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(6 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(7 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>( 8 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>( 9 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(10 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(11 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(12 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>(13 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(14 * ELEMENTS, false));
EXPECT_FALSE(reader.getDataField<bool>(15 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS, true ));
EXPECT_FALSE(reader.getDataField<bool>(64 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(64 * ELEMENTS, false));
EXPECT_TRUE (reader.getDataField<bool>(64 * ELEMENTS, true )); EXPECT_FALSE(reader.getDataField<bool>(0 * ELEMENTS, true));
EXPECT_TRUE (reader.getDataField<bool>(1 * ELEMENTS, true));
EXPECT_FALSE(reader.getDataField<bool>(63 * ELEMENTS, true));
EXPECT_TRUE (reader.getDataField<bool>(64 * ELEMENTS, true));
} }
static const AlignedData<6> STRUCT_DEFAULT = {{0,0,0,0,2,0,4,0, 0}};
static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}};
static const AlignedData<3> STRUCTLIST_ELEMENT_DEFAULT = static const AlignedData<3> STRUCTLIST_ELEMENT_DEFAULT =
{{0,0,0,0,1,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}}; {{0,0,0,0,1,0,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}};
...@@ -106,7 +118,8 @@ static void setupStruct(StructBuilder builder) { ...@@ -106,7 +118,8 @@ static void setupStruct(StructBuilder builder) {
builder.setDataField<bool>(127 * ELEMENTS, false); builder.setDataField<bool>(127 * ELEMENTS, false);
{ {
StructBuilder subStruct = builder.initStructField(0 * REFERENCES, SUBSTRUCT_DEFAULT.words); StructBuilder subStruct = builder.initStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES));
subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123); subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123);
} }
...@@ -120,12 +133,12 @@ static void setupStruct(StructBuilder builder) { ...@@ -120,12 +133,12 @@ static void setupStruct(StructBuilder builder) {
{ {
ListBuilder list = builder.initStructListField( ListBuilder list = builder.initStructListField(
2 * REFERENCES, 4 * ELEMENTS, STRUCTLIST_ELEMENT_DEFAULT.words); 2 * REFERENCES, 4 * ELEMENTS, StructSize(1 * WORDS, 1 * REFERENCES));
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, 2 * WORDS / ELEMENTS, 1 * WORDS);
element.setDataField<int32_t>(0 * ELEMENTS, 300 + i); element.setDataField<int32_t>(0 * ELEMENTS, 300 + i);
element.initStructField(0 * REFERENCES, STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) element.initStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES))
.setDataField<int32_t>(0 * ELEMENTS, 400 + i); .setDataField<int32_t>(0 * ELEMENTS, 400 + i);
} }
} }
...@@ -159,7 +172,8 @@ static void checkStruct(StructBuilder builder) { ...@@ -159,7 +172,8 @@ static void checkStruct(StructBuilder builder) {
EXPECT_FALSE(builder.getDataField<bool>(127 * ELEMENTS)); EXPECT_FALSE(builder.getDataField<bool>(127 * ELEMENTS));
{ {
StructBuilder subStruct = builder.getStructField(0 * REFERENCES, SUBSTRUCT_DEFAULT.words); StructBuilder subStruct = builder.getStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES), SUBSTRUCT_DEFAULT.words);
EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS)); EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS));
} }
...@@ -178,7 +192,8 @@ static void checkStruct(StructBuilder builder) { ...@@ -178,7 +192,8 @@ static void checkStruct(StructBuilder builder) {
StructBuilder element = list.getStructElement(i * ELEMENTS, 2 * WORDS / ELEMENTS, 1 * WORDS); StructBuilder element = list.getStructElement(i * ELEMENTS, 2 * WORDS / ELEMENTS, 1 * WORDS);
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, STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) element.getStructField(0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES),
STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words)
.getDataField<int32_t>(0 * ELEMENTS)); .getDataField<int32_t>(0 * ELEMENTS));
} }
} }
...@@ -197,22 +212,22 @@ static void checkStruct(StructBuilder builder) { ...@@ -197,22 +212,22 @@ static void checkStruct(StructBuilder builder) {
} }
static void checkStruct(StructReader reader) { static void checkStruct(StructReader reader) {
EXPECT_EQ(0x1011121314151617ull, reader.getDataField<uint64_t>(0 * ELEMENTS, 1616)); EXPECT_EQ(0x1011121314151617ull, reader.getDataField<uint64_t>(0 * ELEMENTS));
EXPECT_EQ(0x20212223u, reader.getDataField<uint32_t>(2 * ELEMENTS, 1616)); EXPECT_EQ(0x20212223u, reader.getDataField<uint32_t>(2 * ELEMENTS));
EXPECT_EQ(0x3031u, reader.getDataField<uint16_t>(6 * ELEMENTS, 1616)); EXPECT_EQ(0x3031u, reader.getDataField<uint16_t>(6 * ELEMENTS));
EXPECT_EQ(0x40u, reader.getDataField<uint8_t>(14 * ELEMENTS, 16)); EXPECT_EQ(0x40u, reader.getDataField<uint8_t>(14 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(120 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(120 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(121 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(121 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(122 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(122 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(123 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(123 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(124 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(124 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(125 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(125 * ELEMENTS));
EXPECT_TRUE (reader.getDataField<bool>(126 * ELEMENTS, false)); EXPECT_TRUE (reader.getDataField<bool>(126 * ELEMENTS));
EXPECT_FALSE(reader.getDataField<bool>(127 * ELEMENTS, false)); EXPECT_FALSE(reader.getDataField<bool>(127 * ELEMENTS));
{ {
StructReader subStruct = reader.getStructField(0 * REFERENCES, SUBSTRUCT_DEFAULT.words); StructReader subStruct = reader.getStructField(0 * REFERENCES, SUBSTRUCT_DEFAULT.words);
EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS, 456)); EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS));
} }
{ {
...@@ -227,11 +242,11 @@ static void checkStruct(StructReader reader) { ...@@ -227,11 +242,11 @@ static void checkStruct(StructReader reader) {
ListReader list = reader.getListField(2 * REFERENCES, FieldSize::INLINE_COMPOSITE, nullptr); ListReader list = reader.getListField(2 * REFERENCES, FieldSize::INLINE_COMPOSITE, 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++) {
StructReader element = list.getStructElement(i * ELEMENTS, STRUCTLIST_ELEMENT_DEFAULT.words); StructReader element = list.getStructElement(i * ELEMENTS);
EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS, 1616)); EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS));
EXPECT_EQ(400 + i, EXPECT_EQ(400 + i,
element.getStructField(0 * REFERENCES, STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) element.getStructField(0 * REFERENCES, STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words)
.getDataField<int32_t>(0 * ELEMENTS, 1616)); .getDataField<int32_t>(0 * ELEMENTS));
} }
} }
...@@ -255,7 +270,8 @@ TEST(WireFormat, StructRoundTrip_OneSegment) { ...@@ -255,7 +270,8 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS); SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS);
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(segment, rootLocation, STRUCT_DEFAULT.words); StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
setupStruct(builder); setupStruct(builder);
// word count: // word count:
...@@ -280,8 +296,8 @@ TEST(WireFormat, StructRoundTrip_OneSegment) { ...@@ -280,8 +296,8 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
checkStruct(builder); checkStruct(builder);
checkStruct(builder.asReader()); checkStruct(builder.asReader());
checkStruct(StructReader::readRootTrusted(segment->getStartPtr(), nullptr)); checkStruct(StructReader::readRootTrusted(segment->getStartPtr()));
checkStruct(StructReader::readRoot(segment->getStartPtr(), nullptr, segment, 4)); checkStruct(StructReader::readRoot(segment->getStartPtr(), segment, 4));
} }
TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
...@@ -290,7 +306,8 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { ...@@ -290,7 +306,8 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS); SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS);
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(segment, rootLocation, STRUCT_DEFAULT.words); StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
setupStruct(builder); setupStruct(builder);
// Verify that we made 15 segments. // Verify that we made 15 segments.
...@@ -317,7 +334,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { ...@@ -317,7 +334,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
checkStruct(builder); checkStruct(builder);
checkStruct(builder.asReader()); checkStruct(builder.asReader());
checkStruct(StructReader::readRoot(segment->getStartPtr(), nullptr, segment, 4)); checkStruct(StructReader::readRoot(segment->getStartPtr(), segment, 4));
} }
TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
...@@ -326,7 +343,8 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { ...@@ -326,7 +343,8 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS); SegmentBuilder* segment = arena.getSegmentWithAvailable(1 * WORDS);
word* rootLocation = segment->allocate(1 * WORDS); word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(segment, rootLocation, STRUCT_DEFAULT.words); StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES));
setupStruct(builder); setupStruct(builder);
// Verify that we made 6 segments. // Verify that we made 6 segments.
...@@ -344,7 +362,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { ...@@ -344,7 +362,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
checkStruct(builder); checkStruct(builder);
checkStruct(builder.asReader()); checkStruct(builder.asReader());
checkStruct(StructReader::readRoot(segment->getStartPtr(), nullptr, segment, 4)); checkStruct(StructReader::readRoot(segment->getStartPtr(), segment, 4));
} }
} // namespace } // namespace
......
...@@ -129,6 +129,10 @@ struct WireReference { ...@@ -129,6 +129,10 @@ struct WireReference {
dataSize.set(ds); dataSize.set(ds);
refCount.set(rc); refCount.set(rc);
} }
CAPNPROTO_ALWAYS_INLINE(void set(StructSize size)) {
dataSize.set(size.data);
refCount.set(size.pointers);
}
} structRef; } structRef;
// Also covers capabilities. // Also covers capabilities.
...@@ -403,47 +407,42 @@ struct WireHelpers { ...@@ -403,47 +407,42 @@ struct WireHelpers {
// ----------------------------------------------------------------- // -----------------------------------------------------------------
static CAPNPROTO_ALWAYS_INLINE(StructBuilder initStructReference( static CAPNPROTO_ALWAYS_INLINE(StructBuilder initStructReference(
WireReference* ref, SegmentBuilder* segment, const word* typeDefaultValue)) { WireReference* ref, SegmentBuilder* segment, StructSize size)) {
const WireReference* defaultRef = reinterpret_cast<const WireReference*>(typeDefaultValue); // Allocate space for the new struct. Newly-allocated space is automatically zeroed.
word* ptr = allocate(ref, segment, size.total(), WireReference::STRUCT);
// Allocate space for the new struct.
word* ptr = allocate(ref, segment, defaultRef->structRef.wordSize(), WireReference::STRUCT);
// Copy over the data segment from the default value. We don't have to copy the reference
// segment because it is presumed to be all-null.
memcpy(ptr, defaultRef->target(),
defaultRef->structRef.dataSize.get() * BYTES_PER_WORD / BYTES);
// Initialize the reference. // Initialize the reference.
ref->structRef.set(defaultRef->structRef.dataSize.get(), defaultRef->structRef.refCount.get()); ref->structRef.set(size);
// Build the StructBuilder. // Build the StructBuilder.
return StructBuilder(segment, ptr, return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data));
reinterpret_cast<WireReference*>(ptr + defaultRef->structRef.dataSize.get()));
} }
static CAPNPROTO_ALWAYS_INLINE(StructBuilder getWritableStructReference( static CAPNPROTO_ALWAYS_INLINE(StructBuilder getWritableStructReference(
WireReference* ref, SegmentBuilder* segment, const word* defaultValue)) { WireReference* ref, SegmentBuilder* segment, StructSize size, const word* defaultValue)) {
const WireReference* defaultRef = reinterpret_cast<const WireReference*>(defaultValue);
word* ptr; word* ptr;
if (ref->isNull()) { if (ref->isNull()) {
ptr = copyMessage(segment, ref, defaultRef); if (defaultValue == nullptr) {
ptr = allocate(ref, segment, size.total(), WireReference::STRUCT);
ref->structRef.set(size);
} else {
ptr = copyMessage(segment, ref, reinterpret_cast<const WireReference*>(defaultValue));
}
} else { } else {
ptr = followFars(ref, segment); ptr = followFars(ref, segment);
CAPNPROTO_DEBUG_ASSERT(ref->kind() == WireReference::STRUCT, CAPNPROTO_DEBUG_ASSERT(ref->kind() == WireReference::STRUCT,
"Called getStruct{Field,Element}() but existing reference is not a struct."); "Called getStruct{Field,Element}() but existing reference is not a struct.");
CAPNPROTO_DEBUG_ASSERT( CAPNPROTO_DEBUG_ASSERT(
ref->structRef.dataSize.get() == defaultRef->structRef.dataSize.get(), ref->structRef.dataSize.get() == size.data,
"Trying to update struct with incorrect data size."); "Trying to update struct with incorrect data size.");
CAPNPROTO_DEBUG_ASSERT( CAPNPROTO_DEBUG_ASSERT(
ref->structRef.refCount.get() == defaultRef->structRef.refCount.get(), ref->structRef.refCount.get() == size.pointers,
"Trying to update struct with incorrect reference count."); "Trying to update struct with incorrect reference count.");
} }
return StructBuilder(segment, ptr, return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data));
reinterpret_cast<WireReference*>(ptr + defaultRef->structRef.dataSize.get()));
} }
static CAPNPROTO_ALWAYS_INLINE(ListBuilder initListReference( static CAPNPROTO_ALWAYS_INLINE(ListBuilder initListReference(
...@@ -468,10 +467,8 @@ struct WireHelpers { ...@@ -468,10 +467,8 @@ struct WireHelpers {
static CAPNPROTO_ALWAYS_INLINE(ListBuilder initStructListReference( static CAPNPROTO_ALWAYS_INLINE(ListBuilder initStructListReference(
WireReference* ref, SegmentBuilder* segment, ElementCount elementCount, WireReference* ref, SegmentBuilder* segment, ElementCount elementCount,
const word* elementDefaultValue)) { StructSize elementSize)) {
const WireReference* defaultRef = reinterpret_cast<const WireReference*>(elementDefaultValue); auto wordsPerElement = elementSize.total() / ELEMENTS;
auto wordsPerElement = defaultRef->structRef.wordSize() / ELEMENTS;
// Allocate the list, prefixed by a single WireReference. // Allocate the list, prefixed by a single WireReference.
WordCount wordCount = elementCount * wordsPerElement; WordCount wordCount = elementCount * wordsPerElement;
...@@ -484,22 +481,9 @@ struct WireHelpers { ...@@ -484,22 +481,9 @@ struct WireHelpers {
// Initialize the list tag. // Initialize the list tag.
reinterpret_cast<WireReference*>(ptr)->setKindAndInlineCompositeListElementCount( reinterpret_cast<WireReference*>(ptr)->setKindAndInlineCompositeListElementCount(
WireReference::STRUCT, elementCount); WireReference::STRUCT, elementCount);
reinterpret_cast<WireReference*>(ptr)->structRef.set( reinterpret_cast<WireReference*>(ptr)->structRef.set(elementSize);
defaultRef->structRef.dataSize.get(),
defaultRef->structRef.refCount.get());
ptr += REFERENCE_SIZE_IN_WORDS; ptr += REFERENCE_SIZE_IN_WORDS;
// Initialize the elements. We only have to copy the data segments, as the reference segment
// in a struct type default value is always all-null.
ByteCount elementDataByteSize = defaultRef->structRef.dataSize.get() * BYTES_PER_WORD;
const word* defaultData = defaultRef->target();
word* elementPtr = ptr;
uint n = elementCount / ELEMENTS;
for (uint i = 0; i < n; i++) {
memcpy(elementPtr, defaultData, elementDataByteSize / BYTES);
elementPtr += 1 * ELEMENTS * wordsPerElement;
}
// Build the ListBuilder. // Build the ListBuilder.
return ListBuilder(segment, ptr, elementCount); return ListBuilder(segment, ptr, elementCount);
} }
...@@ -618,6 +602,10 @@ struct WireHelpers { ...@@ -618,6 +602,10 @@ struct WireHelpers {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
if (defaultValue == nullptr) {
return StructReader(nullptr, nullptr, nullptr, 0 * WORDS, 0 * REFERENCES, 0 * BITS,
std::numeric_limits<int>::max());
}
segment = nullptr; segment = nullptr;
ref = reinterpret_cast<const WireReference*>(defaultValue); ref = reinterpret_cast<const WireReference*>(defaultValue);
ptr = ref->target(); ptr = ref->target();
...@@ -940,25 +928,26 @@ struct WireHelpers { ...@@ -940,25 +928,26 @@ struct WireHelpers {
// ======================================================================================= // =======================================================================================
StructBuilder StructBuilder::initRoot( StructBuilder StructBuilder::initRoot(
SegmentBuilder* segment, word* location, const word* defaultValue) { SegmentBuilder* segment, word* location, StructSize size) {
return WireHelpers::initStructReference( return WireHelpers::initStructReference(
reinterpret_cast<WireReference*>(location), segment, defaultValue); reinterpret_cast<WireReference*>(location), segment, size);
} }
StructBuilder StructBuilder::getRoot( StructBuilder StructBuilder::getRoot(
SegmentBuilder* segment, word* location, const word* defaultValue) { SegmentBuilder* segment, word* location, StructSize size) {
return WireHelpers::getWritableStructReference( return WireHelpers::getWritableStructReference(
reinterpret_cast<WireReference*>(location), segment, defaultValue); reinterpret_cast<WireReference*>(location), segment, size, nullptr);
} }
StructBuilder StructBuilder::initStructField( StructBuilder StructBuilder::initStructField(
WireReferenceCount refIndex, const word* typeDefaultValue) const { WireReferenceCount refIndex, StructSize size) const {
return WireHelpers::initStructReference(references + refIndex, segment, typeDefaultValue); return WireHelpers::initStructReference(references + refIndex, segment, size);
} }
StructBuilder StructBuilder::getStructField( StructBuilder StructBuilder::getStructField(
WireReferenceCount refIndex, const word* defaultValue) const { WireReferenceCount refIndex, StructSize size, const word* defaultValue) const {
return WireHelpers::getWritableStructReference(references + refIndex, segment, defaultValue); return WireHelpers::getWritableStructReference(
references + refIndex, segment, size, defaultValue);
} }
ListBuilder StructBuilder::initListField( ListBuilder StructBuilder::initListField(
...@@ -969,10 +958,9 @@ ListBuilder StructBuilder::initListField( ...@@ -969,10 +958,9 @@ ListBuilder StructBuilder::initListField(
} }
ListBuilder StructBuilder::initStructListField( ListBuilder StructBuilder::initStructListField(
WireReferenceCount refIndex, ElementCount elementCount, WireReferenceCount refIndex, ElementCount elementCount, StructSize elementSize) const {
const word* elementDefaultValue) const {
return WireHelpers::initStructListReference( return WireHelpers::initStructListReference(
references + refIndex, segment, elementCount, elementDefaultValue); references + refIndex, segment, elementCount, elementSize);
} }
ListBuilder StructBuilder::getListField( ListBuilder StructBuilder::getListField(
...@@ -1016,20 +1004,25 @@ StructReader StructBuilder::asReader() const { ...@@ -1016,20 +1004,25 @@ StructReader StructBuilder::asReader() const {
0xffff * WORDS, 0xffff * REFERENCES, 0 * BITS, std::numeric_limits<int>::max()); 0xffff * WORDS, 0xffff * REFERENCES, 0 * BITS, std::numeric_limits<int>::max());
} }
StructReader StructReader::readRootTrusted(const word* location, const word* defaultValue) { StructReader StructReader::readRootTrusted(const word* location) {
return WireHelpers::readStructReference(nullptr, reinterpret_cast<const WireReference*>(location), return WireHelpers::readStructReference(nullptr, reinterpret_cast<const WireReference*>(location),
defaultValue, std::numeric_limits<int>::max()); nullptr, std::numeric_limits<int>::max());
} }
StructReader StructReader::readRoot(const word* location, const word* defaultValue, StructReader StructReader::readRoot(
SegmentReader* segment, int nestingLimit) { const word* location, SegmentReader* segment, int nestingLimit) {
if (!segment->containsInterval(location, location + REFERENCE_SIZE_IN_WORDS)) { if (!segment->containsInterval(location, location + REFERENCE_SIZE_IN_WORDS)) {
segment->getArena()->reportInvalidData("Root location out-of-bounds."); segment->getArena()->reportInvalidData("Root location out-of-bounds.");
location = nullptr; location = nullptr;
} }
return WireHelpers::readStructReference(segment, reinterpret_cast<const WireReference*>(location), return WireHelpers::readStructReference(segment, reinterpret_cast<const WireReference*>(location),
defaultValue, nestingLimit); nullptr, nestingLimit);
}
StructReader StructReader::readEmpty() {
return StructReader(nullptr, nullptr, nullptr, 0 * WORDS, 0 * REFERENCES, 0 * BITS,
std::numeric_limits<int>::max());
} }
StructReader StructReader::getStructField( StructReader StructReader::getStructField(
...@@ -1072,10 +1065,10 @@ ListBuilder ListBuilder::initListElement( ...@@ -1072,10 +1065,10 @@ ListBuilder ListBuilder::initListElement(
} }
ListBuilder ListBuilder::initStructListElement( ListBuilder ListBuilder::initStructListElement(
WireReferenceCount index, ElementCount elementCount, const word* elementDefaultValue) const { WireReferenceCount index, ElementCount elementCount, StructSize elementSize) const {
return WireHelpers::initStructListReference( return WireHelpers::initStructListReference(
reinterpret_cast<WireReference*>(ptr) + index, segment, reinterpret_cast<WireReference*>(ptr) + index, segment,
elementCount, elementDefaultValue); elementCount, elementSize);
} }
ListBuilder ListBuilder::getListElement(WireReferenceCount index) const { ListBuilder ListBuilder::getListElement(WireReferenceCount index) const {
...@@ -1123,11 +1116,11 @@ ListReader ListBuilder::asReader(WordCount dataSize, WireReferenceCount referenc ...@@ -1123,11 +1116,11 @@ ListReader ListBuilder::asReader(WordCount dataSize, WireReferenceCount referenc
dataSize, referenceCount, std::numeric_limits<int>::max()); dataSize, referenceCount, std::numeric_limits<int>::max());
} }
StructReader ListReader::getStructElement(ElementCount index, const word* defaultValue) const { StructReader ListReader::getStructElement(ElementCount index) const {
if (CAPNPROTO_EXPECT_FALSE((segment != nullptr) & (nestingLimit == 0))) { if (CAPNPROTO_EXPECT_FALSE((segment != nullptr) & (nestingLimit == 0))) {
segment->getArena()->reportInvalidData( segment->getArena()->reportInvalidData(
"Message is too deeply-nested or contains cycles. See capnproto::ReadOptions."); "Message is too deeply-nested or contains cycles. See capnproto::ReadOptions.");
return WireHelpers::readStructReference(nullptr, nullptr, defaultValue, nestingLimit); return StructReader::readEmpty();
} else { } else {
BitCount64 indexBit = ElementCount64(index) * stepBits; BitCount64 indexBit = ElementCount64(index) * stepBits;
const byte* structPtr = reinterpret_cast<const byte*>(ptr) + indexBit / BITS_PER_BYTE; const byte* structPtr = reinterpret_cast<const byte*>(ptr) + indexBit / BITS_PER_BYTE;
......
...@@ -123,6 +123,91 @@ union AlignedData { ...@@ -123,6 +123,91 @@ union AlignedData {
word words[wordCount]; word words[wordCount];
}; };
struct StructSize {
WordCount16 data;
WireReferenceCount16 pointers;
inline constexpr WordCount total() const { return data + pointers * WORDS_PER_REFERENCE; }
StructSize() = default;
inline constexpr StructSize(WordCount data, WireReferenceCount pointers)
: data(data), pointers(pointers) {}
};
template <typename T>
class IsEnum {
// Detects whether a primitive value is an enum.
typedef char no;
typedef long yes;
static no test(int i);
static yes test(...);
public:
static constexpr bool value = sizeof(test(T())) == sizeof(yes);
};
// -------------------------------------------------------------------
// Masking of default values
template <typename T, bool isEnum = IsEnum<T>::value> struct MaskType { typedef T Type; };
template <typename T> struct MaskType<T, false> { typedef T Type; };
template <typename T> struct MaskType<T, true> { typedef uint16_t Type; };
template <> struct MaskType<float, false> { typedef uint32_t Type; };
template <> struct MaskType<double, false> { typedef uint64_t Type; };
template <typename T>
CAPNPROTO_ALWAYS_INLINE(
typename MaskType<T>::Type mask(T value, typename MaskType<T>::Type mask));
template <typename T>
CAPNPROTO_ALWAYS_INLINE(
T unmask(typename MaskType<T>::Type value, typename MaskType<T>::Type mask));
template <typename T>
inline typename MaskType<T>::Type mask(T value, typename MaskType<T>::Type mask) {
return static_cast<typename MaskType<T>::Type>(value) ^ mask;
}
template <>
inline uint32_t mask<float>(float value, uint32_t mask) {
uint32_t i;
static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?");
memcpy(&i, &value, sizeof(value));
return i ^ mask;
}
template <>
inline uint64_t mask<double>(double value, uint64_t mask) {
uint64_t i;
static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?");
memcpy(&i, &value, sizeof(value));
return i ^ mask;
}
template <typename T>
inline T unmask(typename MaskType<T>::Type value, typename MaskType<T>::Type mask) {
return static_cast<T>(value ^ mask);
}
template <>
inline float unmask<float>(uint32_t value, uint32_t mask) {
value ^= mask;
float result;
static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?");
memcpy(&result, &value, sizeof(value));
return result;
}
template <>
inline double unmask<double>(uint64_t value, uint64_t mask) {
value ^= mask;
double result;
static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?");
memcpy(&result, &value, sizeof(value));
return result;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
template <typename T> template <typename T>
...@@ -154,30 +239,42 @@ class StructBuilder { ...@@ -154,30 +239,42 @@ class StructBuilder {
public: public:
inline StructBuilder(): segment(nullptr), data(nullptr), references(nullptr) {} inline StructBuilder(): segment(nullptr), data(nullptr), references(nullptr) {}
static StructBuilder initRoot(SegmentBuilder* segment, word* location, const word* defaultValue); static StructBuilder initRoot(SegmentBuilder* segment, word* location, StructSize size);
static StructBuilder getRoot(SegmentBuilder* segment, word* location, const word* defaultValue); static StructBuilder getRoot(SegmentBuilder* segment, word* location, StructSize size);
template <typename T> template <typename T>
CAPNPROTO_ALWAYS_INLINE(T getDataField(ElementCount offset) const); CAPNPROTO_ALWAYS_INLINE(T getDataField(ElementCount offset) const);
// Gets the data field value of the given type at the given offset. The offset is measured in // Gets the data field value of the given type at the given offset. The offset is measured in
// multiples of the field size, determined by the type. // multiples of the field size, determined by the type.
template <typename T>
CAPNPROTO_ALWAYS_INLINE(T getDataField(
ElementCount offset, typename MaskType<T>::Type mask) const);
// Like getDataField() but applies the given XOR mask to the data on load. Used for reading
// fields with non-zero default values.
template <typename T> template <typename T>
CAPNPROTO_ALWAYS_INLINE(void setDataField( CAPNPROTO_ALWAYS_INLINE(void setDataField(
ElementCount offset, typename NoInfer<T>::Type value) const); ElementCount offset, typename NoInfer<T>::Type value) const);
// Sets the data field value at the given offset. // Sets the data field value at the given offset.
StructBuilder initStructField(WireReferenceCount refIndex, const word* typeDefaultValue) const; template <typename T>
CAPNPROTO_ALWAYS_INLINE(void setDataField(
ElementCount offset, typename NoInfer<T>::Type value, typename MaskType<T>::Type mask) const);
// Like setDataField() but applies the given XOR mask before storing. Used for writing fields
// with non-zero default values.
StructBuilder initStructField(WireReferenceCount refIndex, StructSize size) const;
// Initializes the struct field at the given index in the reference segment. If it is already // Initializes the struct field at the given index in the reference segment. If it is already
// initialized, the previous value is discarded or overwritten. The struct is initialized to // initialized, the previous value is discarded or overwritten. The struct is initialized to
// match the given default value (a trusted message). This must be the default value for the // the type's default state (all-zero). Use getStructField() if you want the struct to be
// *type*, not the specific field, and in particular its reference segment is expected to be // initialized as a copy of the field's default value (which may have non-null references).
// all nulls (only the data segment is copied). Use getStructField() if you want the struct
// to be initialized as a copy of the field's default value (which may have non-null references).
StructBuilder getStructField(WireReferenceCount refIndex, const word* defaultValue) const; StructBuilder getStructField(WireReferenceCount refIndex, StructSize size,
const word* defaultValue) const;
// Gets the struct field at the given index in the reference segment. If the field is not already // Gets the struct field at the given index in the reference segment. If the field is not already
// initialized, it is initialized as a deep copy of the given default value (a trusted message). // initialized, it is initialized as a deep copy of the given default value (a trusted message),
// or to the empty state if defaultValue is nullptr.
ListBuilder initListField(WireReferenceCount refIndex, FieldSize elementSize, ListBuilder initListField(WireReferenceCount refIndex, FieldSize elementSize,
ElementCount elementCount) const; ElementCount elementCount) const;
...@@ -185,11 +282,9 @@ public: ...@@ -185,11 +282,9 @@ public:
// segment, and return a pointer to it. All elements are initialized to zero. // segment, and return a pointer to it. All elements are initialized to zero.
ListBuilder initStructListField(WireReferenceCount refIndex, ElementCount elementCount, ListBuilder initStructListField(WireReferenceCount refIndex, ElementCount elementCount,
const word* elementDefaultValue) 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 as a copy of // segment, and return a pointer to it. Each element is initialized to its empty state.
// elementDefaultValue. As with initStructField(), this should be the default value for the
// *type*, with all-null references.
ListBuilder getListField(WireReferenceCount refIndex, const word* defaultValue) const; ListBuilder getListField(WireReferenceCount refIndex, const word* defaultValue) const;
// Gets the already-allocated list field for the given reference index. If the list is not // Gets the already-allocated list field for the given reference index. If the list is not
...@@ -234,21 +329,27 @@ public: ...@@ -234,21 +329,27 @@ public:
: segment(nullptr), data(nullptr), references(nullptr), dataSize(0), : segment(nullptr), data(nullptr), references(nullptr), dataSize(0),
referenceCount(0), bit0Offset(0 * BITS), nestingLimit(0) {} referenceCount(0), bit0Offset(0 * BITS), nestingLimit(0) {}
static StructReader readRootTrusted(const word* location, const word* defaultValue); static StructReader readRootTrusted(const word* location);
static StructReader readRoot(const word* location, const word* defaultValue, static StructReader readRoot(const word* location, SegmentReader* segment, int nestingLimit);
SegmentReader* segment, int nestingLimit); static StructReader readEmpty();
template <typename T> template <typename T>
CAPNPROTO_ALWAYS_INLINE( CAPNPROTO_ALWAYS_INLINE(T getDataField(ElementCount offset) const);
T getDataField(ElementCount offset, typename NoInfer<T>::Type defaultValue) const);
// Get the data field value of the given type at the given offset. The offset is measured in // Get the data field value of the given type at the given offset. The offset is measured in
// multiples of the field size, determined by the type. Returns the default value if the offset // multiples of the field size, determined by the type. Returns zero if the offset is past the
// is past the end of the struct's data segment. // end of the struct's data segment.
template <typename T>
CAPNPROTO_ALWAYS_INLINE(
T getDataField(ElementCount offset, typename MaskType<T>::Type mask) const);
// Like getDataField(offset), but applies the given XOR mask to the result. Used for reading
// fields with non-zero default values.
StructReader getStructField(WireReferenceCount refIndex, const word* defaultValue) const; StructReader getStructField(WireReferenceCount refIndex, const word* defaultValue) const;
// Get the struct field at the given index in the reference segment, or the default value if not // Get the struct field at the given index in the reference segment, or the default value if not
// initialized. defaultValue will be interpreted as a trusted message -- it must point at a // initialized. defaultValue will be interpreted as a trusted message -- it must point at a
// struct reference, which in turn points at the struct value. // struct reference, which in turn points at the struct value. The default value is allowed to
// be null, in which case an empty struct is used.
ListReader getListField(WireReferenceCount refIndex, FieldSize expectedElementSize, ListReader getListField(WireReferenceCount refIndex, FieldSize expectedElementSize,
const word* defaultValue) const; const word* defaultValue) const;
...@@ -322,11 +423,9 @@ public: ...@@ -322,11 +423,9 @@ public:
// to zero. // to zero.
ListBuilder initStructListElement(WireReferenceCount index, ElementCount elementCount, ListBuilder initStructListElement(WireReferenceCount index, ElementCount elementCount,
const word* elementDefaultValue) 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 as a copy of // segment, and return a pointer to it. Each element is initialized to its empty state.
// elementDefaultValue. As with StructBuilder::initStructListElement(), this should be the
// default value for the *type*, with all-null references.
ListBuilder getListElement(WireReferenceCount index) const; ListBuilder getListElement(WireReferenceCount 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
...@@ -378,7 +477,7 @@ public: ...@@ -378,7 +477,7 @@ public:
CAPNPROTO_ALWAYS_INLINE(T getDataElement(ElementCount index) const); CAPNPROTO_ALWAYS_INLINE(T getDataElement(ElementCount index) const);
// Get the element of the given type at the given index. // Get the element of the given type at the given index.
StructReader getStructElement(ElementCount index, const word* defaultValue) 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(WireReferenceCount index, FieldSize expectedElementSize) const;
...@@ -451,6 +550,11 @@ inline Void StructBuilder::getDataField<Void>(ElementCount offset) const { ...@@ -451,6 +550,11 @@ inline Void StructBuilder::getDataField<Void>(ElementCount offset) const {
return Void::VOID; return Void::VOID;
} }
template <typename T>
inline T StructBuilder::getDataField(ElementCount offset, typename MaskType<T>::Type mask) const {
return unmask<T>(getDataField<typename MaskType<T>::Type>(offset), mask);
}
template <typename T> template <typename T>
inline void StructBuilder::setDataField( inline void StructBuilder::setDataField(
ElementCount offset, typename NoInfer<T>::Type value) const { ElementCount offset, typename NoInfer<T>::Type value) const {
...@@ -469,19 +573,25 @@ inline void StructBuilder::setDataField<bool>(ElementCount offset, bool value) c ...@@ -469,19 +573,25 @@ inline void StructBuilder::setDataField<bool>(ElementCount offset, bool value) c
template <> template <>
inline void StructBuilder::setDataField<Void>(ElementCount offset, Void value) const {} inline void StructBuilder::setDataField<Void>(ElementCount offset, Void value) const {}
template <typename T>
inline void StructBuilder::setDataField(
ElementCount offset, typename NoInfer<T>::Type value, typename MaskType<T>::Type m) const {
setDataField<typename MaskType<T>::Type>(offset, mask<T>(value, m));
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
template <typename T> template <typename T>
T StructReader::getDataField(ElementCount offset, typename NoInfer<T>::Type defaultValue) const { T StructReader::getDataField(ElementCount offset) const {
if (offset * bytesPerElement<T>() < dataSize * BYTES_PER_WORD) { if (offset * bytesPerElement<T>() < dataSize * BYTES_PER_WORD) {
return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get(); return reinterpret_cast<const WireValue<T>*>(data)[offset / ELEMENTS].get();
} else { } else {
return defaultValue; return static_cast<T>(0);
} }
} }
template <> template <>
inline bool StructReader::getDataField<bool>(ElementCount offset, bool defaultValue) const { inline bool StructReader::getDataField<bool>(ElementCount offset) const {
BitCount boffset = offset * (1 * BITS / ELEMENTS); BitCount boffset = offset * (1 * BITS / ELEMENTS);
// This branch should always be optimized away when inlining. // This branch should always be optimized away when inlining.
...@@ -491,15 +601,20 @@ inline bool StructReader::getDataField<bool>(ElementCount offset, bool defaultVa ...@@ -491,15 +601,20 @@ inline bool StructReader::getDataField<bool>(ElementCount offset, bool defaultVa
const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE; const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE;
return (*reinterpret_cast<const uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; return (*reinterpret_cast<const uint8_t*>(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0;
} else { } else {
return defaultValue; return false;
} }
} }
template <> template <>
inline Void StructReader::getDataField<Void>(ElementCount offset, Void defaultValue) const { inline Void StructReader::getDataField<Void>(ElementCount offset) const {
return Void::VOID; return Void::VOID;
} }
template <typename T>
T StructReader::getDataField(ElementCount offset, typename MaskType<T>::Type mask) const {
return unmask<T>(getDataField<typename MaskType<T>::Type>(offset), mask);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline ElementCount ListBuilder::size() { return elementCount; } inline ElementCount ListBuilder::size() { return elementCount; }
......
...@@ -216,7 +216,7 @@ struct List<T, false> { ...@@ -216,7 +216,7 @@ struct List<T, false> {
inline uint size() { return reader.size() / ELEMENTS; } inline uint size() { return reader.size() / ELEMENTS; }
inline typename T::Reader operator[](uint index) { inline typename T::Reader operator[](uint index) {
return typename T::Reader(reader.getStructElement(index * ELEMENTS, T::DEFAULT.words)); return typename T::Reader(reader.getStructElement(index * ELEMENTS));
} }
typedef internal::IndexingIterator<Reader, typename T::Reader> iterator; typedef internal::IndexingIterator<Reader, typename T::Reader> iterator;
...@@ -235,8 +235,7 @@ struct List<T, false> { ...@@ -235,8 +235,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::DATA_SIZE + T::REFERENCE_COUNT * WORDS_PER_REFERENCE) / ELEMENTS, T::STRUCT_SIZE.total() / ELEMENTS, T::STRUCT_SIZE.data));
T::DATA_SIZE));
} }
typedef internal::IndexingIterator<Builder, typename T::Builder> iterator; typedef internal::IndexingIterator<Builder, typename T::Builder> iterator;
......
...@@ -38,7 +38,7 @@ MessageReader::~MessageReader() { ...@@ -38,7 +38,7 @@ MessageReader::~MessageReader() {
} }
} }
internal::StructReader MessageReader::getRoot(const word* defaultValue) { internal::StructReader MessageReader::getRootInternal() {
if (!allocatedArena) { if (!allocatedArena) {
static_assert(sizeof(internal::ReaderArena) <= sizeof(arenaSpace), static_assert(sizeof(internal::ReaderArena) <= sizeof(arenaSpace),
"arenaSpace is too small to hold a ReaderArena. Please increase it. This will break " "arenaSpace is too small to hold a ReaderArena. Please increase it. This will break "
...@@ -51,10 +51,9 @@ internal::StructReader MessageReader::getRoot(const word* defaultValue) { ...@@ -51,10 +51,9 @@ internal::StructReader MessageReader::getRoot(const word* defaultValue) {
if (segment == nullptr || if (segment == nullptr ||
!segment->containsInterval(segment->getStartPtr(), segment->getStartPtr() + 1)) { !segment->containsInterval(segment->getStartPtr(), segment->getStartPtr() + 1)) {
arena()->reportInvalidData("Message did not contain a root pointer."); arena()->reportInvalidData("Message did not contain a root pointer.");
return internal::StructReader::readRootTrusted(defaultValue, defaultValue); return internal::StructReader::readEmpty();
} else { } else {
return internal::StructReader::readRoot( return internal::StructReader::readRoot(segment->getStartPtr(), segment, options.nestingLimit);
segment->getStartPtr(), defaultValue, segment, options.nestingLimit);
} }
} }
...@@ -88,16 +87,16 @@ internal::SegmentBuilder* MessageBuilder::getRootSegment() { ...@@ -88,16 +87,16 @@ internal::SegmentBuilder* MessageBuilder::getRootSegment() {
} }
} }
internal::StructBuilder MessageBuilder::initRoot(const word* defaultValue) { internal::StructBuilder MessageBuilder::initRoot(internal::StructSize size) {
internal::SegmentBuilder* rootSegment = getRootSegment(); internal::SegmentBuilder* rootSegment = getRootSegment();
return internal::StructBuilder::initRoot( return internal::StructBuilder::initRoot(
rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), defaultValue); rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), size);
} }
internal::StructBuilder MessageBuilder::getRoot(const word* defaultValue) { internal::StructBuilder MessageBuilder::getRoot(internal::StructSize size) {
internal::SegmentBuilder* rootSegment = getRootSegment(); internal::SegmentBuilder* rootSegment = getRootSegment();
return internal::StructBuilder::getRoot( return internal::StructBuilder::getRoot(
rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), defaultValue); rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), size);
} }
ArrayPtr<const ArrayPtr<const word>> MessageBuilder::getSegmentsForOutput() { ArrayPtr<const ArrayPtr<const word>> MessageBuilder::getSegmentsForOutput() {
......
...@@ -144,7 +144,7 @@ private: ...@@ -144,7 +144,7 @@ private:
bool allocatedArena; bool allocatedArena;
internal::ReaderArena* arena() { return reinterpret_cast<internal::ReaderArena*>(arenaSpace); } internal::ReaderArena* arena() { return reinterpret_cast<internal::ReaderArena*>(arenaSpace); }
internal::StructReader getRoot(const word* defaultValue); internal::StructReader getRootInternal();
}; };
class MessageBuilder { class MessageBuilder {
...@@ -175,8 +175,8 @@ private: ...@@ -175,8 +175,8 @@ private:
internal::BuilderArena* arena() { return reinterpret_cast<internal::BuilderArena*>(arenaSpace); } internal::BuilderArena* arena() { return reinterpret_cast<internal::BuilderArena*>(arenaSpace); }
internal::SegmentBuilder* getRootSegment(); internal::SegmentBuilder* getRootSegment();
internal::StructBuilder initRoot(const word* defaultValue); internal::StructBuilder initRoot(internal::StructSize size);
internal::StructBuilder getRoot(const word* defaultValue); internal::StructBuilder getRoot(internal::StructSize size);
}; };
template <typename RootType> template <typename RootType>
...@@ -297,23 +297,22 @@ inline const ReaderOptions& MessageReader::getOptions() { ...@@ -297,23 +297,22 @@ inline const ReaderOptions& MessageReader::getOptions() {
template <typename RootType> template <typename RootType>
inline typename RootType::Reader MessageReader::getRoot() { inline typename RootType::Reader MessageReader::getRoot() {
return typename RootType::Reader(getRoot(RootType::DEFAULT.words)); return typename RootType::Reader(getRootInternal());
} }
template <typename RootType> template <typename RootType>
inline typename RootType::Builder MessageBuilder::initRoot() { inline typename RootType::Builder MessageBuilder::initRoot() {
return typename RootType::Builder(initRoot(RootType::DEFAULT.words)); return typename RootType::Builder(initRoot(RootType::STRUCT_SIZE));
} }
template <typename RootType> template <typename RootType>
inline typename RootType::Builder MessageBuilder::getRoot() { inline typename RootType::Builder MessageBuilder::getRoot() {
return typename RootType::Builder(getRoot(RootType::DEFAULT.words)); return typename RootType::Builder(getRoot(RootType::STRUCT_SIZE));
} }
template <typename RootType> template <typename RootType>
typename RootType::Reader readMessageTrusted(const word* data) { typename RootType::Reader readMessageTrusted(const word* data) {
return typename RootType::Reader(internal::StructReader::readRootTrusted( return typename RootType::Reader(internal::StructReader::readRootTrusted(data));
data, RootType::DEFAULT.words));
} }
} // namespace capnproto } // namespace capnproto
......
...@@ -67,7 +67,7 @@ struct TestAllTypes { ...@@ -67,7 +67,7 @@ struct TestAllTypes {
dataList @30 : List(Data); dataList @30 : List(Data);
structList @31 : List(TestAllTypes); structList @31 : List(TestAllTypes);
enumList @32 : List(TestEnum); enumList @32 : List(TestEnum);
interfaceList @33 : Void; # TODO interfaceList @33 : List(Void); # TODO
} }
struct TestDefaults { struct TestDefaults {
......
...@@ -29,6 +29,7 @@ import qualified Data.ByteString.UTF8 as ByteStringUTF8 ...@@ -29,6 +29,7 @@ import qualified Data.ByteString.UTF8 as ByteStringUTF8
import Data.FileEmbed(embedFile) import Data.FileEmbed(embedFile)
import Data.Word(Word8) import Data.Word(Word8)
import qualified Data.Digest.MD5 as MD5 import qualified Data.Digest.MD5 as MD5
import Data.Binary.IEEE754(floatToWord, doubleToWord)
import Text.Printf(printf) import Text.Printf(printf)
import Text.Hastache import Text.Hastache
import Text.Hastache.Context import Text.Hastache.Context
...@@ -106,25 +107,41 @@ cxxFieldSizeString Size64 = "EIGHT_BYTES"; ...@@ -106,25 +107,41 @@ cxxFieldSizeString Size64 = "EIGHT_BYTES";
cxxFieldSizeString SizeReference = "REFERENCE"; cxxFieldSizeString SizeReference = "REFERENCE";
cxxFieldSizeString (SizeInlineComposite _ _) = "INLINE_COMPOSITE"; cxxFieldSizeString (SizeInlineComposite _ _) = "INLINE_COMPOSITE";
cxxValueString VoidDesc = " ::capnproto::Void::VOID" isDefaultZero VoidDesc = True
cxxValueString (BoolDesc b) = if b then "true" else "false" isDefaultZero (BoolDesc b) = not b
cxxValueString (Int8Desc i) = show i isDefaultZero (Int8Desc i) = i == 0
cxxValueString (Int16Desc i) = show i isDefaultZero (Int16Desc i) = i == 0
cxxValueString (Int32Desc i) = show i isDefaultZero (Int32Desc i) = i == 0
cxxValueString (Int64Desc i) = show i ++ "ll" isDefaultZero (Int64Desc i) = i == 0
cxxValueString (UInt8Desc i) = show i isDefaultZero (UInt8Desc i) = i == 0
cxxValueString (UInt16Desc i) = show i isDefaultZero (UInt16Desc i) = i == 0
cxxValueString (UInt32Desc i) = show i ++ "u" isDefaultZero (UInt32Desc i) = i == 0
cxxValueString (UInt64Desc i) = show i ++ "llu" isDefaultZero (UInt64Desc i) = i == 0
cxxValueString (Float32Desc x) = show x ++ "f" isDefaultZero (Float32Desc x) = x == 0
cxxValueString (Float64Desc x) = show x isDefaultZero (Float64Desc x) = x == 0
cxxValueString (EnumValueValueDesc v) = isDefaultZero (EnumValueValueDesc v) = enumValueNumber v == 0
cxxTypeString (EnumType $ enumValueParent v) ++ "::" ++ isDefaultZero (TextDesc _) = error "Can't call isDefaultZero on aggregate types."
toUpperCaseWithUnderscores (enumValueName v) isDefaultZero (DataDesc _) = error "Can't call isDefaultZero on aggregate types."
cxxValueString (TextDesc _) = error "No default value literal for aggregate type." isDefaultZero (StructValueDesc _) = error "Can't call isDefaultZero on aggregate types."
cxxValueString (DataDesc _) = error "No default value literal for aggregate type." isDefaultZero (ListDesc _) = error "Can't call isDefaultZero on aggregate types."
cxxValueString (StructValueDesc _) = error "No default value literal for aggregate type."
cxxValueString (ListDesc _) = error "No default value literal for aggregate type." defaultMask VoidDesc = "0"
defaultMask (BoolDesc b) = if b then "true" else "false"
defaultMask (Int8Desc i) = show i
defaultMask (Int16Desc i) = show i
defaultMask (Int32Desc i) = show i
defaultMask (Int64Desc i) = show i ++ "ll"
defaultMask (UInt8Desc i) = show i
defaultMask (UInt16Desc i) = show i
defaultMask (UInt32Desc i) = show i ++ "u"
defaultMask (UInt64Desc i) = show i ++ "llu"
defaultMask (Float32Desc x) = show (floatToWord x) ++ "u"
defaultMask (Float64Desc x) = show (doubleToWord x) ++ "ul"
defaultMask (EnumValueValueDesc v) = show (enumValueNumber v)
defaultMask (TextDesc _) = error "Can't call defaultMask on aggregate types."
defaultMask (DataDesc _) = error "Can't call defaultMask on aggregate types."
defaultMask (StructValueDesc _) = error "Can't call defaultMask on aggregate types."
defaultMask (ListDesc _) = error "Can't call defaultMask on aggregate types."
defaultValueBytes _ (TextDesc s) = Just (UTF8.encode s ++ [0]) defaultValueBytes _ (TextDesc s) = Just (UTF8.encode s ++ [0])
defaultValueBytes _ (DataDesc d) = Just d defaultValueBytes _ (DataDesc d) = Just d
...@@ -132,25 +149,6 @@ defaultValueBytes t v@(StructValueDesc _) = Just $ encodeMessage t v ...@@ -132,25 +149,6 @@ defaultValueBytes t v@(StructValueDesc _) = Just $ encodeMessage t v
defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v defaultValueBytes t v@(ListDesc _) = Just $ encodeMessage t v
defaultValueBytes _ _ = Nothing defaultValueBytes _ _ = Nothing
cxxDefaultDefault (BuiltinType BuiltinVoid) = " ::capnproto::Void::VOID"
cxxDefaultDefault (BuiltinType BuiltinBool) = "false"
cxxDefaultDefault (BuiltinType BuiltinInt8) = "0"
cxxDefaultDefault (BuiltinType BuiltinInt16) = "0"
cxxDefaultDefault (BuiltinType BuiltinInt32) = "0"
cxxDefaultDefault (BuiltinType BuiltinInt64) = "0"
cxxDefaultDefault (BuiltinType BuiltinUInt8) = "0"
cxxDefaultDefault (BuiltinType BuiltinUInt16) = "0"
cxxDefaultDefault (BuiltinType BuiltinUInt32) = "0"
cxxDefaultDefault (BuiltinType BuiltinUInt64) = "0"
cxxDefaultDefault (BuiltinType BuiltinFloat32) = "0"
cxxDefaultDefault (BuiltinType BuiltinFloat64) = "0"
cxxDefaultDefault (BuiltinType BuiltinText) = "\"\""
cxxDefaultDefault (EnumType desc) = cxxValueString $ EnumValueValueDesc $ head $ enumValues desc
cxxDefaultDefault (BuiltinType BuiltinData) = error "No default value literal for aggregate type."
cxxDefaultDefault (StructType _) = error "No default value literal for aggregate type."
cxxDefaultDefault (InterfaceType _) = error "No default value literal for aggregate type."
cxxDefaultDefault (ListType _) = error "No default value literal for aggregate type."
elementType (ListType t) = t elementType (ListType t) = t
elementType _ = error "Called elementType on non-list." elementType _ = error "Called elementType on non-list."
...@@ -197,9 +195,9 @@ fieldContext parent desc = mkStrContext context where ...@@ -197,9 +195,9 @@ 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 $ fieldOffset desc context "fieldOffset" = MuVariable $ fieldOffset desc
context "fieldDefaultValue" = case fieldDefaultValue desc of context "fieldDefaultMask" = case fieldDefaultValue desc of
Just v -> MuVariable $ cxxValueString v Nothing -> MuVariable ""
Nothing -> MuVariable $ cxxDefaultDefault $ fieldType desc Just v -> MuVariable (if isDefaultZero v then "" else ", " ++ defaultMask v)
context "fieldElementSize" = context "fieldElementSize" =
MuVariable $ cxxFieldSizeString $ elementSize $ elementType $ fieldType desc MuVariable $ cxxFieldSizeString $ elementSize $ elementType $ fieldType desc
context "fieldElementType" = context "fieldElementType" =
...@@ -212,8 +210,6 @@ structContext parent desc = mkStrContext context where ...@@ -212,8 +210,6 @@ structContext parent desc = mkStrContext context where
context "structDataSize" = MuVariable $ packingDataSize $ structPacking desc context "structDataSize" = MuVariable $ packingDataSize $ structPacking desc
context "structReferenceCount" = MuVariable $ packingReferenceCount $ structPacking desc context "structReferenceCount" = MuVariable $ packingReferenceCount $ structPacking desc
context "structChildren" = MuList [] -- TODO context "structChildren" = MuList [] -- TODO
context "structDefault" = MuList [defaultBytesContext context (StructType desc)
(encodeMessage (StructType desc) (StructValueDesc []))]
context s = parent s context s = parent s
fileContext desc = mkStrContext context where fileContext desc = mkStrContext context where
......
...@@ -25,8 +25,7 @@ module WireFormat(encodeMessage) where ...@@ -25,8 +25,7 @@ module WireFormat(encodeMessage) where
import Data.List(sortBy, genericLength, genericReplicate) import Data.List(sortBy, genericLength, genericReplicate)
import Data.Word import Data.Word
import Data.Bits(shiftL, shiftR, Bits, setBit) import Data.Bits(shiftL, shiftR, Bits, setBit, xor)
import qualified Data.Set as Set
import Semantics import Semantics
import Data.Binary.IEEE754(floatToWord, doubleToWord) import Data.Binary.IEEE754(floatToWord, doubleToWord)
import qualified Codec.Binary.UTF8.String as UTF8 import qualified Codec.Binary.UTF8.String as UTF8
...@@ -69,27 +68,34 @@ encodeDataValue (EnumValueValueDesc v) = bytes (enumValueNumber v) 2 ...@@ -69,27 +68,34 @@ encodeDataValue (EnumValueValueDesc v) = bytes (enumValueNumber v) 2
encodeDataValue (StructValueDesc _) = error "Not fixed-width data." encodeDataValue (StructValueDesc _) = error "Not fixed-width data."
encodeDataValue (ListDesc _) = error "Not fixed-width data." encodeDataValue (ListDesc _) = error "Not fixed-width data."
packBits :: Bits a => Int -> [Bool] -> a encodeMaskedDataValue v Nothing = encodeDataValue v
encodeMaskedDataValue v (Just d) = zipWith xor (encodeDataValue v) (encodeDataValue d)
packBits :: Bits a => Int -> [(Bool, Maybe Bool)] -> a
packBits _ [] = 0 packBits _ [] = 0
packBits offset (True:bits) = setBit (packBits (offset + 1) bits) offset packBits offset ((True, Nothing):bits) = setBit (packBits (offset + 1) bits) offset
packBits offset (False:bits) = packBits (offset + 1) bits packBits offset ((False, Nothing):bits) = packBits (offset + 1) bits
packBits offset ((b, Just d):bits) = packBits offset ((b /= d, Nothing):bits)
encodeData :: Integer -> [(Integer, TypeDesc, ValueDesc)] -> [Word8] -- The tuples are (offsetInBits, type, value, defaultValue) for each field to encode.
encodeData :: Integer -> [(Integer, TypeDesc, ValueDesc, Maybe ValueDesc)] -> [Word8]
encodeData size = loop 0 where encodeData size = loop 0 where
loop bit [] | bit == size = [] loop bit [] | bit == size = []
loop bit [] | bit > size = error "Data values overran size." loop bit [] | bit > size = error "Data values overran size."
loop bit [] = 0:loop (bit + 8) [] loop bit [] = 0:loop (bit + 8) []
loop bit rest@((valuePos, _, BoolDesc _):_) | valuePos == bit = let loop bit rest@((valuePos, _, BoolDesc _, _):_) | valuePos == bit = let
(bits, rest2) = popBits (bit + 8) rest (bits, rest2) = popBits (bit + 8) rest
in packBits 0 bits : loop (bit + 8) rest2 in packBits 0 bits : loop (bit + 8) rest2
loop bit ((valuePos, _, value):rest) | valuePos == bit = loop bit ((valuePos, _, value, defaultValue):rest) | valuePos == bit =
encodeDataValue value ++ loop (bit + sizeInBits (fieldValueSize value)) rest encodeMaskedDataValue value defaultValue ++
loop bit rest@((valuePos, _, _):_) | valuePos > bit = 0 : loop (bit + 8) rest loop (bit + sizeInBits (fieldValueSize value)) rest
loop bit rest@((valuePos, _, _, _):_) | valuePos > bit = 0 : loop (bit + 8) rest
loop _ _ = error "Data values were out-of-order." loop _ _ = error "Data values were out-of-order."
popBits limit ((valuePos, _, BoolDesc b):rest) | valuePos < limit = let popBits limit ((valuePos, _, BoolDesc b, d):rest) | valuePos < limit = let
(restBits, rest2) = popBits limit rest (restBits, rest2) = popBits limit rest
in (b:restBits, rest2) defaultB = fmap (\(BoolDesc b2) -> b2) d
in ((b, defaultB):restBits, rest2)
popBits _ rest = ([], rest) popBits _ rest = ([], rest)
encodeReferences :: Integer -> Integer -> [(Integer, TypeDesc, ValueDesc)] -> ([Word8], [Word8]) encodeReferences :: Integer -> Integer -> [(Integer, TypeDesc, ValueDesc)] -> ([Word8], [Word8])
...@@ -156,10 +162,6 @@ fieldSizeEnum (SizeInlineComposite _ _) = 7 ...@@ -156,10 +162,6 @@ fieldSizeEnum (SizeInlineComposite _ _) = 7
structTag = 0 structTag = 0
listTag = 1 listTag = 1
-- Is this field a non-retroactive member of a union? If so, its default value is not written.
isNonRetroUnionMember (FieldDesc {fieldNumber = n, fieldUnion = Just u}) = n > unionNumber u
isNonRetroUnionMember _ = False
-- What is this union's default tag value? If there is a retroactive field, it is that field's -- What is this union's default tag value? If there is a retroactive field, it is that field's
-- number, otherwise it is the union's number (meaning no field set). -- number, otherwise it is the union's number (meaning no field set).
unionDefault desc = UInt8Desc $ fromIntegral $ unionDefault desc = UInt8Desc $ fromIntegral $
...@@ -168,49 +170,24 @@ unionDefault desc = UInt8Desc $ fromIntegral $ ...@@ -168,49 +170,24 @@ unionDefault desc = UInt8Desc $ fromIntegral $
-- childOffset = number of words between the last reference and the location where children will -- childOffset = number of words between the last reference and the location where children will
-- be allocated. -- be allocated.
encodeStruct desc assignments childOffset = (dataBytes, referenceBytes, children) where encodeStruct desc assignments childOffset = (dataBytes, referenceBytes, children) where
explicitlyAssignedNums = Set.fromList [fieldNumber f | (f, _) <- assignments]
explicitlyAssignedUnions = Set.fromList
[unionNumber u | (FieldDesc {fieldUnion = Just u}, _) <- assignments]
-- Was this field explicitly assigned, or was another member of the same union explicitly
-- assigned? If so, its default value is not written.
isExplicitlyAssigned (FieldDesc {fieldNumber = n, fieldUnion = u}) =
Set.member n explicitlyAssignedNums ||
maybe False (flip Set.member explicitlyAssignedUnions . unionNumber) u
-- Values explicitly assigned. -- Values explicitly assigned.
explicitValues = [(fieldOffset f, fieldType f, v) | (f, v) <- assignments] explicitValues = [(fieldOffset f, fieldType f, v, fieldDefaultValue f) | (f, v) <- assignments]
-- Values from defaults.
defaultValues = [(o, fieldType field, v)
| field@(FieldDesc { fieldOffset = o, fieldDefaultValue = Just v}) <- structFields desc
-- Don't include default values for fields that were explicitly assigned.
, not $ isExplicitlyAssigned field
-- Don't encode defaults for union members since they'd overwrite each other, and anyway
-- they wouldn't be valid unless the union tag specified them, which by default it doesn't,
-- except of course in the case of retroactively-added fields. So do include retro fields.
, not $ isNonRetroUnionMember field
-- Don't encode defaults for references. Setting them to null has the same effect.
, isDataFieldSize $ fieldValueSize v ]
-- Values of union tags. -- Values of union tags.
unionValues = [(unionTagOffset u, BuiltinType BuiltinUInt8, UInt8Desc $ fromIntegral n) unionValues = [(unionTagOffset u, BuiltinType BuiltinUInt8, UInt8Desc $ fromIntegral n,
Just $ unionDefault u)
| (FieldDesc {fieldUnion = Just u, fieldNumber = n}, _) <- assignments] | (FieldDesc {fieldUnion = Just u, fieldNumber = n}, _) <- assignments]
-- Default values of union tags. allValues = explicitValues ++ unionValues
unionDefaultValues = [(unionTagOffset u, BuiltinType BuiltinUInt8, unionDefault u) allData = [ (o * sizeInBits (fieldValueSize v), t, v, d)
| u <- structUnions desc | (o, t, v, d) <- allValues, isDataFieldSize $ fieldValueSize v ]
, not $ Set.member (unionNumber u) explicitlyAssignedUnions] allReferences = [ (o, t, v) | (o, t, v, _) <- allValues
allValues = explicitValues ++ defaultValues ++ unionValues ++ unionDefaultValues
allData = [ (o * sizeInBits (fieldValueSize v), t, v)
| (o, t, v) <- allValues, isDataFieldSize $ fieldValueSize v ]
allReferences = [ (o, t, v) | (o, t, v) <- allValues
, not $ isDataFieldSize $ fieldValueSize v ] , not $ isDataFieldSize $ fieldValueSize v ]
sortedData = sortBy compareValues allData sortedData = sortBy compareDataValues allData
sortedReferences = sortBy compareValues allReferences compareDataValues (o1, _, _, _) (o2, _, _, _) = compare o1 o2
compareValues (o1, _, _) (o2, _, _) = compare o1 o2 sortedReferences = sortBy compareReferenceValues allReferences
compareReferenceValues (o1, _, _) (o2, _, _) = compare o1 o2
dataBytes = encodeData (packingDataSize (structPacking desc) * 64) sortedData dataBytes = encodeData (packingDataSize (structPacking desc) * 64) sortedData
(referenceBytes, children) = encodeReferences childOffset (referenceBytes, children) = encodeReferences childOffset
...@@ -228,7 +205,7 @@ encodeList elementType elements = case elementSize elementType of ...@@ -228,7 +205,7 @@ encodeList elementType elements = case elementSize elementType of
(refBytes, childBytes) = encodeReferences 0 (genericLength elements) (refBytes, childBytes) = encodeReferences 0 (genericLength elements)
$ zipWith (\i v -> (i, elementType, v)) [0..] elements $ zipWith (\i v -> (i, elementType, v)) [0..] elements
size -> encodeData (roundUpToMultiple 64 (genericLength elements * sizeInBits size)) size -> encodeData (roundUpToMultiple 64 (genericLength elements * sizeInBits size))
$ zipWith (\i v -> (i * sizeInBits size, elementType, v)) [0..] elements $ zipWith (\i v -> (i * sizeInBits size, elementType, v, Nothing)) [0..] elements
encodeMessage (StructType desc) (StructValueDesc assignments) = let encodeMessage (StructType desc) (StructValueDesc assignments) = let
(dataBytes, refBytes, childBytes) = encodeStruct desc assignments 0 (dataBytes, refBytes, childBytes) = encodeStruct desc assignments 0
......
...@@ -41,12 +41,9 @@ struct {{structName}} { ...@@ -41,12 +41,9 @@ struct {{structName}} {
struct {{structChildName}}; struct {{structChildName}};
{{/structChildren}} {{/structChildren}}
static constexpr ::capnproto::WordCount DATA_SIZE = {{structDataSize}} * ::capnproto::WORDS; static constexpr ::capnproto::internal::StructSize STRUCT_SIZE =
static constexpr ::capnproto::WireReferenceCount REFERENCE_COUNT = ::capnproto::internal::StructSize({{structDataSize}} * ::capnproto::WORDS,
{{structReferenceCount}} * ::capnproto::REFERENCES; {{structReferenceCount}} * ::capnproto::REFERENCES);
{{#structDefault}}
static const ::capnproto::internal::AlignedData<{{defaultWordCount}}> DEFAULT;
{{/structDefault}}
{{#structFields}} {{#structFields}}
{{#fieldDefaultBytes}} {{#fieldDefaultBytes}}
static const ::capnproto::internal::AlignedData<{{defaultWordCount}}> DEFAULT_{{fieldUpperCase}}; static const ::capnproto::internal::AlignedData<{{defaultWordCount}}> DEFAULT_{{fieldUpperCase}};
...@@ -140,7 +137,7 @@ private: ...@@ -140,7 +137,7 @@ private:
{{#fieldIsPrimitive}} {{#fieldIsPrimitive}}
inline {{fieldType}} {{structName}}::Reader::get{{fieldTitleCase}}() { inline {{fieldType}} {{structName}}::Reader::get{{fieldTitleCase}}() {
return _reader.getDataField<{{fieldType}}>( return _reader.getDataField<{{fieldType}}>(
{{fieldOffset}} * ::capnproto::ELEMENTS, {{fieldDefaultValue}}); {{fieldOffset}} * ::capnproto::ELEMENTS{{fieldDefaultMask}});
} }
{{/fieldIsPrimitive}} {{/fieldIsPrimitive}}
{{#fieldIsBlob}} {{#fieldIsBlob}}
...@@ -159,7 +156,7 @@ inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() { ...@@ -159,7 +156,7 @@ inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() {
return {{fieldType}}::Reader(_reader.getStructField( return {{fieldType}}::Reader(_reader.getStructField(
{{fieldOffset}} * ::capnproto::REFERENCES, {{fieldOffset}} * ::capnproto::REFERENCES,
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}} {{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}{{fieldType}}::DEFAULT.words{{/fieldDefaultBytes}})); {{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
} }
{{/fieldIsStruct}} {{/fieldIsStruct}}
{{#fieldIsList}} {{#fieldIsList}}
...@@ -179,11 +176,12 @@ inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() { ...@@ -179,11 +176,12 @@ inline {{fieldType}}::Reader {{structName}}::Reader::get{{fieldTitleCase}}() {
// {{structName}}.{{fieldDecl}} // {{structName}}.{{fieldDecl}}
{{#fieldIsPrimitive}} {{#fieldIsPrimitive}}
inline {{fieldType}} {{structName}}::Builder::get{{fieldTitleCase}}() { inline {{fieldType}} {{structName}}::Builder::get{{fieldTitleCase}}() {
return _builder.getDataField<{{fieldType}}>({{fieldOffset}} * ::capnproto::ELEMENTS); return _builder.getDataField<{{fieldType}}>(
{{fieldOffset}} * ::capnproto::ELEMENTS{{fieldDefaultMask}});
} }
inline void {{structName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value) { inline void {{structName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value) {
return _builder.setDataField<{{fieldType}}>( return _builder.setDataField<{{fieldType}}>(
{{fieldOffset}} * ::capnproto::ELEMENTS, value); {{fieldOffset}} * ::capnproto::ELEMENTS, value{{fieldDefaultMask}});
} }
{{/fieldIsPrimitive}} {{/fieldIsPrimitive}}
{{#fieldIsBlob}} {{#fieldIsBlob}}
...@@ -205,14 +203,14 @@ inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(un ...@@ -205,14 +203,14 @@ inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(un
{{#fieldIsStruct}} {{#fieldIsStruct}}
inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}() { inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}() {
return {{fieldType}}::Builder(_builder.initStructField( return {{fieldType}}::Builder(_builder.initStructField(
{{fieldOffset}} * ::capnproto::REFERENCES, {{fieldType}}::DEFAULT.words)); {{fieldOffset}} * ::capnproto::REFERENCES, {{fieldType}}::STRUCT_SIZE));
} }
inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() { inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() {
{{! TODO: Support per-field default values. }} {{! TODO: Support per-field default values. }}
return {{fieldType}}::Builder(_builder.getStructField( return {{fieldType}}::Builder(_builder.getStructField(
{{fieldOffset}} * ::capnproto::REFERENCES, {{fieldOffset}} * ::capnproto::REFERENCES, {{fieldType}}::STRUCT_SIZE,
{{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}} {{#fieldDefaultBytes}}DEFAULT_{{fieldUpperCase}}.words{{/fieldDefaultBytes}}
{{^fieldDefaultBytes}}{{fieldType}}::DEFAULT.words{{/fieldDefaultBytes}})); {{^fieldDefaultBytes}}nullptr{{/fieldDefaultBytes}}));
} }
{{/fieldIsStruct}} {{/fieldIsStruct}}
{{#fieldIsNonStructList}} {{#fieldIsNonStructList}}
...@@ -249,7 +247,7 @@ inline void {{structName}}::Builder::set{{fieldTitleCase}}( ...@@ -249,7 +247,7 @@ inline void {{structName}}::Builder::set{{fieldTitleCase}}(
inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(unsigned int size) { inline {{fieldType}}::Builder {{structName}}::Builder::init{{fieldTitleCase}}(unsigned int size) {
return {{fieldType}}::Builder(_builder.initStructListField( return {{fieldType}}::Builder(_builder.initStructListField(
{{fieldOffset}} * ::capnproto::REFERENCES, size * ::capnproto::ELEMENTS, {{fieldOffset}} * ::capnproto::REFERENCES, size * ::capnproto::ELEMENTS,
{{fieldElementType}}::DEFAULT.words)); {{fieldElementType}}::STRUCT_SIZE));
} }
inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() { inline {{fieldType}}::Builder {{structName}}::Builder::get{{fieldTitleCase}}() {
return {{fieldType}}::Builder(_builder.getListField( return {{fieldType}}::Builder(_builder.getListField(
......
...@@ -32,13 +32,7 @@ namespace {{namespaceName}} { ...@@ -32,13 +32,7 @@ namespace {{namespaceName}} {
{{/fileNamespaces}} {{/fileNamespaces}}
{{#fileStructs}} {{#fileStructs}}
constexpr ::capnproto::WordCount {{structName}}::DATA_SIZE; constexpr ::capnproto::internal::StructSize {{structName}}::STRUCT_SIZE;
constexpr ::capnproto::WireReferenceCount {{structName}}::REFERENCE_COUNT;
{{#structDefault}}
const ::capnproto::internal::AlignedData<{{defaultWordCount}}> {{structName}}::DEFAULT = {
{ {{defaultByteList}} }
};
{{/structDefault}}
{{#structFields}} {{#structFields}}
{{#fieldDefaultBytes}} {{#fieldDefaultBytes}}
......
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