Commit de33baaf authored by Kenton Varda's avatar Kenton Varda

Simplify more after removing inline types.

parent 7197456b
......@@ -102,7 +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, 8 * BYTES);
static constexpr StructSize STRUCTLIST_ELEMENT_SIZE(
1 * WORDS, 1 * REFERENCES, FieldSize::INLINE_COMPOSITE);
static void setupStruct(StructBuilder builder) {
builder.setDataField<uint64_t>(0 * ELEMENTS, 0x1011121314151617ull);
......@@ -120,7 +121,7 @@ static void setupStruct(StructBuilder builder) {
{
StructBuilder subStruct = builder.initStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 8 * BYTES));
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, FieldSize::EIGHT_BYTES));
subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123);
}
......@@ -139,7 +140,8 @@ static void setupStruct(StructBuilder builder) {
for (int i = 0; i < 4; i++) {
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, 8 * BYTES))
element.initStructField(0 * REFERENCES,
StructSize(1 * WORDS, 0 * REFERENCES, FieldSize::EIGHT_BYTES))
.setDataField<int32_t>(0 * ELEMENTS, 400 + i);
}
}
......@@ -174,7 +176,8 @@ static void checkStruct(StructBuilder builder) {
{
StructBuilder subStruct = builder.getStructField(
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, 8 * BYTES), SUBSTRUCT_DEFAULT.words);
0 * REFERENCES, StructSize(1 * WORDS, 0 * REFERENCES, FieldSize::EIGHT_BYTES),
SUBSTRUCT_DEFAULT.words);
EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS));
}
......@@ -193,7 +196,8 @@ static void checkStruct(StructBuilder builder) {
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, 8 * BYTES),
element.getStructField(0 * REFERENCES,
StructSize(1 * WORDS, 0 * REFERENCES, FieldSize::EIGHT_BYTES),
STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words)
.getDataField<int32_t>(0 * ELEMENTS));
}
......@@ -272,7 +276,7 @@ TEST(WireFormat, StructRoundTrip_OneSegment) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 16 * BYTES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, FieldSize::INLINE_COMPOSITE));
setupStruct(builder);
// word count:
......@@ -308,7 +312,7 @@ TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 16 * BYTES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, FieldSize::INLINE_COMPOSITE));
setupStruct(builder);
// Verify that we made 15 segments.
......@@ -345,7 +349,7 @@ TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) {
word* rootLocation = segment->allocate(1 * WORDS);
StructBuilder builder = StructBuilder::initRoot(
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, 16 * BYTES));
segment, rootLocation, StructSize(2 * WORDS, 4 * REFERENCES, FieldSize::INLINE_COMPOSITE));
setupStruct(builder);
// Verify that we made 6 segments.
......
......@@ -418,8 +418,7 @@ struct WireHelpers {
ref->structRef.set(size);
// Build the StructBuilder.
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data),
size.pointers);
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data));
}
static CAPNPROTO_ALWAYS_INLINE(StructBuilder getWritableStructReference(
......@@ -446,8 +445,7 @@ struct WireHelpers {
"Trying to update struct with incorrect reference count.");
}
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data),
size.pointers);
return StructBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + size.data));
}
static CAPNPROTO_ALWAYS_INLINE(ListBuilder initListReference(
......@@ -456,6 +454,8 @@ struct WireHelpers {
DPRECOND(elementSize != FieldSize::INLINE_COMPOSITE,
"Should have called initStructListReference() instead.");
// Note: Use bitsPerElement(), not bytesPerElement(), to handle bit lists correctly when
// computing wordCount. After that, the step is not used for bit lists.
auto step = bitsPerElement(elementSize);
// Calculate size of the list.
......@@ -468,30 +468,18 @@ struct WireHelpers {
ref->listRef.set(elementSize, elementCount);
// Build the ListBuilder.
return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr),
step / BITS_PER_BYTE, step / BITS_PER_REFERENCE, elementCount);
return ListBuilder(segment, ptr, step / BITS_PER_BYTE, 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.dataBytes / BYTES) {
case 0: primitiveElementSize = FieldSize::VOID; break;
case 1: primitiveElementSize = FieldSize::BYTE; break;
case 2: primitiveElementSize = FieldSize::TWO_BYTES; break;
case 4: primitiveElementSize = FieldSize::FOUR_BYTES; break;
case 8: primitiveElementSize = FieldSize::EIGHT_BYTES; break;
default: FAIL_PRECOND("Invalid struct size."); break;
}
}
return initListReference(ref, segment, elementCount, primitiveElementSize);
if (elementSize.preferredListEncoding != FieldSize::INLINE_COMPOSITE) {
// Small data-only struct. Allocate a list of primitives instead. Don't ever pack as
// individual bits, though; we don't support that.
return initListReference(ref, segment, elementCount,
elementSize.preferredListEncoding == FieldSize::BIT ?
FieldSize::BYTE : elementSize.preferredListEncoding);
}
auto wordsPerElement = elementSize.total() / ELEMENTS;
......@@ -511,9 +499,7 @@ struct WireHelpers {
ptr += REFERENCE_SIZE_IN_WORDS;
// Build the ListBuilder.
return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr + elementSize.data),
wordsPerElement * BYTES_PER_WORD, wordsPerElement / WORDS_PER_REFERENCE,
elementCount);
return ListBuilder(segment, ptr, wordsPerElement * BYTES_PER_WORD, elementCount);
}
static CAPNPROTO_ALWAYS_INLINE(ListBuilder getWritableListReference(
......@@ -523,8 +509,7 @@ struct WireHelpers {
if (ref->isNull()) {
if (defaultValue == nullptr) {
return ListBuilder(segment, nullptr, nullptr, 0 * BYTES / ELEMENTS,
0 * REFERENCES / ELEMENTS, 0 * ELEMENTS);
return ListBuilder();
}
ptr = copyMessage(segment, ref, defaultRef);
} else {
......@@ -541,17 +526,11 @@ struct WireHelpers {
"INLINE_COMPOSITE list with non-STRUCT elements not supported.");
// First list element is at tag + 1 reference.
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 * BYTES_PER_WORD, step / WORDS_PER_REFERENCE,
return ListBuilder(segment, tag + 1, tag->structRef.wordSize() * BYTES_PER_WORD / ELEMENTS,
tag->inlineCompositeListElementCount());
} else {
auto step = bytesPerElement(ref->listRef.elementSize());
return ListBuilder(segment, ptr, reinterpret_cast<WireReference*>(ptr),
step, step / BYTES_PER_REFERENCE,
ref->listRef.elementCount());
return ListBuilder(segment, ptr, step, ref->listRef.elementCount());
}
}
......@@ -685,9 +664,7 @@ struct WireHelpers {
if (ref == nullptr || ref->isNull()) {
useDefault:
if (defaultValue == nullptr) {
return ListReader(nullptr, nullptr, nullptr, 0 * ELEMENTS,
0 * BYTES / ELEMENTS, 0 * REFERENCES / ELEMENTS,
nestingLimit - 1);
return ListReader();
}
segment = nullptr;
ref = reinterpret_cast<const WireReference*>(defaultValue);
......@@ -795,9 +772,7 @@ struct WireHelpers {
}
return ListReader(
segment, ptr,
reinterpret_cast<const WireReference*>(ptr + tag->structRef.dataSize.get()),
size, wordsPerElement * BYTES_PER_WORD, wordsPerElement / WORDS_PER_REFERENCE,
segment, ptr, size, wordsPerElement * BYTES_PER_WORD,
tag->structRef.dataSize.get() * BYTES_PER_WORD,
tag->structRef.refCount.get(), nestingLimit - 1);
......@@ -814,9 +789,8 @@ struct WireHelpers {
}
if (ref->listRef.elementSize() == expectedElementSize) {
return ListReader(segment, ptr, reinterpret_cast<const WireReference*>(ptr),
ref->listRef.elementCount(), step / BITS_PER_BYTE,
step / BITS_PER_REFERENCE, nestingLimit - 1);
return ListReader(segment, ptr, ref->listRef.elementCount(), step / BITS_PER_BYTE,
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
......@@ -845,9 +819,8 @@ struct WireHelpers {
break;
}
return ListReader(segment, ptr, reinterpret_cast<const WireReference*>(ptr),
ref->listRef.elementCount(), step / BITS_PER_BYTE,
step / BITS_PER_REFERENCE, dataSize, referenceCount, nestingLimit - 1);
return ListReader(segment, ptr, ref->listRef.elementCount(), step / BITS_PER_BYTE,
dataSize, referenceCount, nestingLimit - 1);
} else {
PRECOND(segment != nullptr, "Trusted message had incompatible list element type.");
goto useDefault;
......@@ -1080,102 +1053,124 @@ Data::Reader StructReader::getDataField(
StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const {
// TODO: Inline this method?
ByteCount indexByte = ElementCount64(index) * stepBytes;
byte* structData = reinterpret_cast<byte*>(data) + indexByte;
WireReference* structPointers = pointers + index * stepPointers;
return StructBuilder(segment, structData, structPointers, elementSize.pointers);
byte* structData = ptr + index * stepBytes;
return StructBuilder(segment, structData,
reinterpret_cast<WireReference*>(structData) + elementSize.data / WORDS_PER_REFERENCE);
}
ListBuilder ListBuilder::initListElement(
ElementCount index, FieldSize elementSize, ElementCount elementCount) const {
return WireHelpers::initListReference(
pointers + index * stepPointers, segment,
elementCount, elementSize);
reinterpret_cast<WireReference*>(ptr + index * stepBytes),
segment, elementCount, elementSize);
}
ListBuilder ListBuilder::initStructListElement(
ElementCount index, ElementCount elementCount, StructSize elementSize) const {
return WireHelpers::initStructListReference(
pointers + index * stepPointers, segment,
elementCount, elementSize);
reinterpret_cast<WireReference*>(ptr + index * stepBytes),
segment, elementCount, elementSize);
}
ListBuilder ListBuilder::getListElement(ElementCount index) const {
return WireHelpers::getWritableListReference(
pointers + index * stepPointers, segment, nullptr);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, nullptr);
}
Text::Builder ListBuilder::initTextElement(ElementCount index, ByteCount size) const {
return WireHelpers::initTextReference(
pointers + index * stepPointers, segment, size);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, size);
}
void ListBuilder::setTextElement(ElementCount index, Text::Reader value) const {
WireHelpers::setTextReference(
pointers + index * stepPointers, segment, value);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, value);
}
Text::Builder ListBuilder::getTextElement(ElementCount index) const {
return WireHelpers::getWritableTextReference(
pointers + index * stepPointers, segment, "", 0 * BYTES);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, "", 0 * BYTES);
}
Data::Builder ListBuilder::initDataElement(ElementCount index, ByteCount size) const {
return WireHelpers::initDataReference(
pointers + index * stepPointers, segment, size);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, size);
}
void ListBuilder::setDataElement(ElementCount index, Data::Reader value) const {
WireHelpers::setDataReference(
pointers + index * stepPointers, segment, value);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), segment, value);
}
Data::Builder ListBuilder::getDataElement(ElementCount index) const {
return WireHelpers::getWritableDataReference(
pointers + index * stepPointers, segment, nullptr, 0 * BYTES);
reinterpret_cast<WireReference*>(ptr + index * stepBytes), 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, data, pointers, elementCount, stepBytes, stepPointers,
std::numeric_limits<int>::max());
return ListReader(segment, ptr, elementCount, stepBytes, std::numeric_limits<int>::max());
}
ListReader ListBuilder::asReader(StructSize elementSize) const {
return ListReader(segment, data, pointers, elementCount, stepBytes, stepPointers,
elementSize.dataBytes, elementSize.pointers, std::numeric_limits<int>::max());
DCHECK(stepBytes * ELEMENTS >= elementSize.data * BYTES_PER_WORD ||
(elementSize.data == 1 * WORDS &&
elementSize.preferredListEncoding != FieldSize::INLINE_COMPOSITE &&
elementSize.preferredListEncoding != FieldSize::REFERENCE &&
stepBytes == bytesPerElement(elementSize.preferredListEncoding)),
"Assumptions used here did not hold.");
return ListReader(segment, ptr, elementCount, stepBytes,
std::min(stepBytes * ELEMENTS, elementSize.data * BYTES_PER_WORD),
elementSize.pointers,
std::numeric_limits<int>::max());
}
// =======================================================================================
// ListReader
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();
}
ByteCount indexByte = index * stepBytes;
const byte* structData = reinterpret_cast<const byte*>(data) + indexByte;
const byte* structData = ptr + indexByte;
const WireReference* structPointers =
reinterpret_cast<const WireReference*>(structData + structDataSize);
// This check should pass if there are no bugs in the list pointer validation code.
DCHECK(structReferenceCount == 0 * REFERENCES ||
(uintptr_t)structPointers % sizeof(WireReference) == 0,
"Pointer segment of struct list element not aligned.");
return StructReader(
segment, structData, pointers + index * stepPointers,
segment, structData, structPointers,
structDataSize, structReferenceCount, nestingLimit - 1);
}
static const WireReference* checkAlignment(const void* ptr) {
DCHECK((uintptr_t)ptr % sizeof(WireReference) == 0,
"Pointer segment of struct list element not aligned.");
return reinterpret_cast<const WireReference*>(ptr);
}
ListReader ListReader::getListElement(
ElementCount index, FieldSize expectedElementSize) const {
return WireHelpers::readListReference(
segment, pointers + index * stepPointers,
segment, checkAlignment(ptr + index * stepBytes),
nullptr, expectedElementSize, nestingLimit);
}
Text::Reader ListReader::getTextElement(ElementCount index) const {
return WireHelpers::readTextReference(
segment, pointers + index * stepPointers, "", 0 * BYTES);
segment, checkAlignment(ptr + index * stepBytes),
"", 0 * BYTES);
}
Data::Reader ListReader::getDataElement(ElementCount index) const {
return WireHelpers::readDataReference(
segment, pointers + index * stepPointers, nullptr, 0 * BYTES);
segment, checkAlignment(ptr + index * stepBytes),
nullptr, 0 * BYTES);
}
} // namespace internal
......
......@@ -28,11 +28,6 @@
// as does other parts of the Cap'n proto library which provide a higher-level interface for
// dynamic introspection.
#ifdef __CDT_PARSER__
// Eclipse keeps thinking this is pre-defined for no apparent reason.
#undef CAPNPROTO_LAYOUT_H_
#endif
#ifndef CAPNPROTO_LAYOUT_H_
#define CAPNPROTO_LAYOUT_H_
......@@ -137,15 +132,17 @@ struct StructSize {
WordCount16 data;
WireReferenceCount16 pointers;
ByteCount32 dataBytes;
// Number of bytes in the data section. Must be data * 8 except when data == 1 in which case
// this can be 1, 2, 4, or 8.
FieldSize preferredListEncoding;
// Preferred size to use when encoding a list of this struct. This is INLINE_COMPOSITE if and
// only if the struct is larger than one word; otherwise the struct list can be encoded more
// efficiently by encoding it as if it were some primitive type.
inline constexpr WordCount total() const { return data + pointers * WORDS_PER_REFERENCE; }
StructSize() = default;
inline constexpr StructSize(WordCount data, WireReferenceCount pointers, ByteCount dataBytes)
: data(data), pointers(pointers), dataBytes(dataBytes) {}
inline constexpr StructSize(WordCount data, WireReferenceCount pointers,
FieldSize preferredListEncoding)
: data(data), pointers(pointers), preferredListEncoding(preferredListEncoding) {}
};
template <typename T>
......@@ -325,20 +322,13 @@ 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.
WireReference* references; // Pointer to the encoded references.
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,
WireReferenceCount referenceCount)
: segment(segment), data(data), references(references),
referenceCount(referenceCount) {}
inline StructBuilder(SegmentBuilder* segment, void* data, WireReference* references)
: segment(segment), data(data), references(references) {}
friend class ListBuilder;
friend struct WireHelpers;
......@@ -393,7 +383,10 @@ private:
const void* data;
const WireReference* references;
ByteCount32 dataSize; // Size of data segment.
ByteCount32 dataSize;
// Size of data segment. We use a byte count rather than a word count to more easily handle the
// case of struct lists encoded with less than a word per element.
WireReferenceCount16 referenceCount; // Size of the reference segment.
int nestingLimit;
......@@ -417,8 +410,8 @@ private:
class ListBuilder {
public:
inline ListBuilder()
: segment(nullptr), data(nullptr), pointers(nullptr), elementCount(0 * ELEMENTS),
stepBytes(0 * BYTES / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS) {}
: segment(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS),
stepBytes(0 * BYTES / ELEMENTS) {}
inline ElementCount size();
// The number of elements in the list.
......@@ -449,10 +442,6 @@ public:
// Get the existing list element at the given index. Returns an empty list if the element is
// not initialized.
CAPNPROTO_ALWAYS_INLINE(ListBuilder slice(ElementCount start, ElementCount length) const);
// Get a list pointing at a slice of this list. WARNING: The second parameter is a length, not
// an end index, because this is what is most convenient at the only call site.
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.
......@@ -477,22 +466,18 @@ public:
private:
SegmentBuilder* segment; // Memory segment in which the list resides.
void* data;
WireReference* pointers;
// Pointers to list content.
byte* ptr; // Pointer to list content.
ElementCount elementCount; // Number of elements in the list.
decltype(BYTES / ELEMENTS) stepBytes;
decltype(REFERENCES / ELEMENTS) stepPointers;
// The distance between elements. Can be tricky e.g. for inlined struct lists.
// The distance between elements.
// Bit lists ignore stepBytes -- they are always tightly-packed.
inline ListBuilder(SegmentBuilder* segment, void* data, WireReference* pointers,
decltype(BYTES / ELEMENTS) stepBytes,
decltype(REFERENCES / ELEMENTS) stepPointers, ElementCount size)
: segment(segment), data(data), pointers(pointers), elementCount(size),
stepBytes(stepBytes), stepPointers(stepPointers) {}
inline ListBuilder(SegmentBuilder* segment, void* ptr,
decltype(BYTES / ELEMENTS) stepBytes, ElementCount size)
: segment(segment), ptr(reinterpret_cast<byte*>(ptr)),
elementCount(size), stepBytes(stepBytes) {}
friend class StructBuilder;
friend struct WireHelpers;
......@@ -501,8 +486,7 @@ private:
class ListReader {
public:
inline ListReader()
: segment(nullptr), data(nullptr), pointers(nullptr), elementCount(0),
stepBytes(0 * BYTES / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS),
: segment(nullptr), ptr(nullptr), elementCount(0), stepBytes(0 * BYTES / ELEMENTS),
structDataSize(0), structReferenceCount(0), nestingLimit(0) {}
inline ElementCount size();
......@@ -518,10 +502,6 @@ public:
ListReader getListElement(ElementCount index, FieldSize expectedElementSize) const;
// Get the list element at the given index.
CAPNPROTO_ALWAYS_INLINE(ListReader slice(ElementCount start, ElementCount length) const);
// Get a list pointing at a slice of this list. WARNING: The second parameter is a length, not
// an end index, because this is what is most convenient at the only call site.
Text::Reader getTextElement(ElementCount index) const;
// Get the text element. If it is not initialized, returns an empty Text::Reader.
......@@ -531,15 +511,12 @@ public:
private:
SegmentReader* segment; // Memory segment in which the list resides.
const void* data;
const WireReference* pointers;
// Pointers to list content.
const byte* ptr; // Pointer to list content.
ElementCount elementCount; // Number of elements in the list.
decltype(BYTES / ELEMENTS) stepBytes;
decltype(REFERENCES / ELEMENTS) stepPointers;
// The distance between elements. Can be tricky e.g. for inlined struct lists.
// The distance between elements.
// Bit lists ignore stepBytes -- they are always tightly-packed.
ByteCount structDataSize;
......@@ -550,18 +527,18 @@ private:
// 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* data, const WireReference* pointers,
inline ListReader(SegmentReader* segment, const void* ptr,
ElementCount elementCount, decltype(BYTES / ELEMENTS) stepBytes,
decltype(REFERENCES / ELEMENTS) stepPointers, int nestingLimit)
: segment(segment), data(data), pointers(pointers), elementCount(elementCount),
stepBytes(stepBytes), stepPointers(stepPointers), structDataSize(0),
structReferenceCount(0), nestingLimit(nestingLimit) {}
inline ListReader(SegmentReader* segment, const void* data, const WireReference* pointers,
int nestingLimit)
: segment(segment), ptr(reinterpret_cast<const byte*>(ptr)), elementCount(elementCount),
stepBytes(stepBytes), structDataSize(0), structReferenceCount(0),
nestingLimit(nestingLimit) {}
inline ListReader(SegmentReader* segment, const void* ptr,
ElementCount elementCount, decltype(BYTES / ELEMENTS) stepBytes,
decltype(REFERENCES / ELEMENTS) stepPointers, ByteCount structDataSize,
WireReferenceCount structReferenceCount, int nestingLimit)
: segment(segment), data(data), pointers(pointers), elementCount(elementCount),
stepBytes(stepBytes), stepPointers(stepPointers), structDataSize(structDataSize),
ByteCount structDataSize, WireReferenceCount structReferenceCount,
int nestingLimit)
: segment(segment), ptr(reinterpret_cast<const byte*>(ptr)), elementCount(elementCount),
stepBytes(stepBytes), structDataSize(structDataSize),
structReferenceCount(structReferenceCount), nestingLimit(nestingLimit) {}
friend class StructReader;
......@@ -656,15 +633,14 @@ inline ElementCount ListBuilder::size() { return elementCount; }
template <typename T>
inline T ListBuilder::getDataElement(ElementCount index) const {
return reinterpret_cast<WireValue<T>*>(
reinterpret_cast<byte*>(data) + index * stepBytes)->get();
return reinterpret_cast<WireValue<T>*>(ptr + index * stepBytes)->get();
}
template <>
inline bool ListBuilder::getDataElement<bool>(ElementCount index) const {
// Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists.
BitCount bindex = index * (1 * BITS / ELEMENTS);
byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
byte* b = ptr + bindex / BITS_PER_BYTE;
return (*reinterpret_cast<uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0;
}
......@@ -675,15 +651,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>*>(
reinterpret_cast<byte*>(data) + index * stepBytes)->set(value);
reinterpret_cast<WireValue<T>*>(ptr + index * stepBytes)->set(value);
}
template <>
inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) const {
// Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists.
BitCount bindex = index * (1 * BITS / ELEMENTS);
byte* b = reinterpret_cast<byte*>(data) + bindex / BITS_PER_BYTE;
byte* b = ptr + 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);
......@@ -692,29 +667,20 @@ inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) co
template <>
inline void ListBuilder::setDataElement<Void>(ElementCount index, Void value) const {}
inline ListBuilder ListBuilder::slice(ElementCount start, ElementCount length) const {
return ListBuilder(segment,
reinterpret_cast<byte*>(data) + start * stepBytes,
reinterpret_cast<WireReference*>(
reinterpret_cast<word*>(pointers) + start * stepPointers * WORDS_PER_REFERENCE),
stepBytes, stepPointers, length);
}
// -------------------------------------------------------------------
inline ElementCount ListReader::size() { return elementCount; }
template <typename T>
inline T ListReader::getDataElement(ElementCount index) const {
return reinterpret_cast<const WireValue<T>*>(
reinterpret_cast<const byte*>(data) + index * stepBytes)->get();
return reinterpret_cast<const WireValue<T>*>(ptr + index * stepBytes)->get();
}
template <>
inline bool ListReader::getDataElement<bool>(ElementCount index) const {
// Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists.
BitCount bindex = index * (1 * BITS / ELEMENTS);
const byte* b = reinterpret_cast<const byte*>(data) + bindex / BITS_PER_BYTE;
const byte* b = ptr + bindex / BITS_PER_BYTE;
return (*reinterpret_cast<const uint8_t*>(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0;
}
......@@ -723,14 +689,6 @@ inline Void ListReader::getDataElement<Void>(ElementCount index) const {
return Void::VOID;
}
inline ListReader ListReader::slice(ElementCount start, ElementCount length) const {
return ListReader(segment,
reinterpret_cast<const byte*>(data) + start * stepBytes,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(pointers) + start * stepPointers * WORDS_PER_REFERENCE),
length, stepBytes, stepPointers, structDataSize, structReferenceCount, nestingLimit);
}
} // namespace internal
} // namespace capnproto
......
......@@ -353,6 +353,15 @@ public:
unit1PerUnit2 / other.unit1PerUnit2);
}
template <typename OtherNumber>
inline decltype(Number(1) / OtherNumber(1))
operator/(UnitRatio<OtherNumber, Unit1, Unit2> other) const {
return unit1PerUnit2 / other.unit1PerUnit2;
}
inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; }
inline bool operator!=(UnitRatio other) const { return unit1PerUnit2 != other.unit1PerUnit2; }
private:
Number unit1PerUnit2;
......
......@@ -379,8 +379,16 @@ 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 "structDataBytes" = MuVariable (div (dataSectionBits (structDataSize desc)) 8)
context "structReferenceCount" = MuVariable $ structPointerCount desc
context "structPreferredListEncoding" = case (structDataSize desc, structPointerCount desc) of
(DataSectionWords 0, 0) -> MuVariable "VOID"
(DataSection1, 0) -> MuVariable "BYTE"
(DataSection8, 0) -> MuVariable "BYTE"
(DataSection16, 0) -> MuVariable "TWO_BYTES"
(DataSection32, 0) -> MuVariable "FOUR_BYTES"
(DataSectionWords 1, 0) -> MuVariable "EIGHT_BYTES"
(DataSectionWords 0, 1) -> MuVariable "REFERENCE"
_ -> MuVariable "INLINE_COMPOSITE"
context "structNestedEnums" =
MuList $ map (enumContext context) [m | DescEnum m <- structMembers desc]
context "structNestedStructs" =
......
......@@ -68,9 +68,10 @@ struct {{typeFullName}} {
{{/structNestedEnums}}
static constexpr ::capnproto::internal::StructSize STRUCT_SIZE =
::capnproto::internal::StructSize({{structDataSize}} * ::capnproto::WORDS,
{{structReferenceCount}} * ::capnproto::REFERENCES,
{{structDataBytes}} * ::capnproto::BYTES);
::capnproto::internal::StructSize(
{{structDataSize}} * ::capnproto::WORDS,
{{structReferenceCount}} * ::capnproto::REFERENCES,
::capnproto::internal::FieldSize::{{structPreferredListEncoding}});
{{/typeStruct}}
{{#typeUnion}}
......
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