Commit c1d973e7 authored by Matthew Maurer's avatar Matthew Maurer

Moved canonicalization onto struct readers.

You can now spawn a canonical message from:
* StructReader
* AnyStruct::Reader
* capnpc-c++ generated Foo::Reader
parent 39a846fa
...@@ -470,6 +470,10 @@ public: ...@@ -470,6 +470,10 @@ public:
return List<AnyPointer>::Reader(_reader.getPointerSectionAsList()); return List<AnyPointer>::Reader(_reader.getPointerSectionAsList());
} }
kj::Array<word> canonicalize() {
return _reader.canonicalize();
}
Equality equals(AnyStruct::Reader right); Equality equals(AnyStruct::Reader right);
bool operator==(AnyStruct::Reader right); bool operator==(AnyStruct::Reader right);
inline bool operator!=(AnyStruct::Reader right) { inline bool operator!=(AnyStruct::Reader right) {
......
...@@ -27,15 +27,17 @@ ...@@ -27,15 +27,17 @@
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
using test::TestLists;
namespace { namespace {
KJ_TEST("canonicalize yields cannonical message") { KJ_TEST("canonicalize yields cannonical message") {
MallocMessageBuilder builder; MallocMessageBuilder builder;
auto root = builder.initRoot<TestAllTypes>(); auto root = builder.initRoot<TestAllTypes>();
initTestMessage(root); initTestMessage(root);
canonicalize(builder); root.asReader().canonicalize();
//Will assert if canonicalize failed to do so //Will assert if canonicalize failed to do so
} }
...@@ -118,6 +120,30 @@ KJ_TEST("isCanonical requires truncation of 0-valued struct fields") { ...@@ -118,6 +120,30 @@ KJ_TEST("isCanonical requires truncation of 0-valued struct fields") {
KJ_ASSERT(!nonTruncated.isCanonical()); KJ_ASSERT(!nonTruncated.isCanonical());
} }
KJ_TEST("upgraded lists can be canonicalized") {
AlignedData<7> upgradedList = {{
//Struct pointer, data immediately follows, 4 pointer fields, no data
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
//Three words of default pointers to get to the int16 list
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//List pointer, 3 int16s.
0x01, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
//First two elements
0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06,
//Last element
0x07, 0x08, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00
}};
kj::ArrayPtr<const word> segments[1] = {
kj::arrayPtr(upgradedList.words, 7)
};
SegmentArrayMessageReader upgraded(kj::arrayPtr(segments, 1));
auto root = upgraded.getRoot<TestLists>();
root.canonicalize();
}
KJ_TEST("isCanonical requires truncation of 0-valued struct fields in all list members") { KJ_TEST("isCanonical requires truncation of 0-valued struct fields in all list members") {
AlignedData<6> nonTruncatedList = {{ AlignedData<6> nonTruncatedList = {{
//List pointer, composite, //List pointer, composite,
......
...@@ -1747,6 +1747,10 @@ private: ...@@ -1747,6 +1747,10 @@ private:
" return _reader.totalSize().asPublic();\n" " return _reader.totalSize().asPublic();\n"
" }\n" " }\n"
"\n" "\n"
" ::kj::Array<::capnp::word> canonicalize() {\n"
" return _reader.canonicalize();\n"
" }\n"
"\n"
"#if !CAPNP_LITE\n" "#if !CAPNP_LITE\n"
" inline ::kj::StringTree toString() const {\n" " inline ::kj::StringTree toString() const {\n"
" return ::capnp::_::structString(_reader, *_capnpPrivate::brand);\n" " return ::capnp::_::structString(_reader, *_capnpPrivate::brand);\n"
......
...@@ -2732,6 +2732,19 @@ MessageSizeCounts StructReader::totalSize() const { ...@@ -2732,6 +2732,19 @@ MessageSizeCounts StructReader::totalSize() const {
return result; return result;
} }
kj::Array<word> StructReader::canonicalize() {
WordCount size = totalSize().wordCount + POINTER_SIZE_IN_WORDS;
kj::Array<word> backing = kj::heapArray<word>(size / WORDS);
memset(backing.begin(), 0, backing.asBytes().size());
FlatMessageBuilder builder(backing);
_::PointerHelpers<AnyPointer>::getInternalBuilder(builder.initRoot<AnyPointer>()).setStruct(*this, true);
KJ_ASSERT(builder.isCanonical());
auto output = builder.getSegmentsForOutput()[0];
kj::Array<word> trunc = kj::heapArray<word>(output.size());
memcpy(trunc.begin(), output.begin(), output.asBytes().size());
return trunc;
}
CapTableReader* StructReader::getCapTable() { CapTableReader* StructReader::getCapTable() {
return capTable; return capTable;
} }
......
...@@ -571,6 +571,8 @@ public: ...@@ -571,6 +571,8 @@ public:
inline kj::ArrayPtr<const byte> getDataSectionAsBlob(); inline kj::ArrayPtr<const byte> getDataSectionAsBlob();
inline _::ListReader getPointerSectionAsList(); inline _::ListReader getPointerSectionAsList();
kj::Array<word> canonicalize();
template <typename T> template <typename T>
KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const); KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const);
// Return true if the field is set to something other than its default value. // Return true if the field is set to something other than its default value.
......
...@@ -421,21 +421,6 @@ private: ...@@ -421,21 +421,6 @@ private:
bool allocated; bool allocated;
}; };
template <typename MR>
kj::Array<word> canonicalize(MR&& reader) {
AnyPointer::Reader root = reader.template getRoot<AnyPointer>();
WordCount size = root.targetSize().wordCount * WORDS + POINTER_SIZE_IN_WORDS;
kj::Array<word> backing = kj::heapArray<word>(size / WORDS);
bzero(backing.begin(), backing.asBytes().size());
FlatMessageBuilder builder(backing);
builder.initRoot<AnyPointer>().setCanonical(root);
KJ_ASSERT(builder.isCanonical());
auto output = builder.getSegmentsForOutput()[0];
kj::Array<word> trunc = kj::heapArray<word>(output.size());
memcpy(trunc.begin(), output.begin(), output.asBytes().size());
return trunc;
}
// ======================================================================================= // =======================================================================================
// implementation details // implementation details
......
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