Commit e607fc95 authored by Kenton Varda's avatar Kenton Varda

Allow getting readers from const Orphans, and other tweaks.

parent 719eb094
...@@ -151,7 +151,7 @@ struct Declaration { ...@@ -151,7 +151,7 @@ struct Declaration {
methodDecl @15 :Method; methodDecl @15 :Method;
annotationDecl @16 :Annotation; annotationDecl @16 :Annotation;
nakedId @21 :UInt64; nakedId @21 :LocatedInteger;
nakedAnnotation @22 :AnnotationApplication; nakedAnnotation @22 :AnnotationApplication;
# A floating UID or annotation (allowed at the file top level). # A floating UID or annotation (allowed at the file top level).
} }
...@@ -221,9 +221,5 @@ struct Declaration { ...@@ -221,9 +221,5 @@ struct Declaration {
} }
struct ParsedFile { struct ParsedFile {
id @0 :UInt64; root @0 :Declaration;
annotations @1 :List(Declaration.AnnotationApplication);
docComment @2 :Text;
topDecls @3 :List(Declaration);
} }
...@@ -44,7 +44,7 @@ uint64_t randomId() { ...@@ -44,7 +44,7 @@ uint64_t randomId() {
KJ_SYSCALL(n = read(fd, &result, sizeof(result)), "/dev/urandom"); KJ_SYSCALL(n = read(fd, &result, sizeof(result)), "/dev/urandom");
KJ_ASSERT(n == sizeof(result), "Incomplete read from /dev/urandom.", n); KJ_ASSERT(n == sizeof(result), "Incomplete read from /dev/urandom.", n);
return result; return result | (1ull << 63);
} }
} // namespace } // namespace
...@@ -56,7 +56,7 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result, ...@@ -56,7 +56,7 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result,
kj::Vector<Orphan<Declaration>> decls(statements.size()); kj::Vector<Orphan<Declaration>> decls(statements.size());
kj::Vector<Orphan<Declaration::AnnotationApplication>> annotations; kj::Vector<Orphan<Declaration::AnnotationApplication>> annotations;
bool sawId = false; auto fileDecl = result.getRoot();
for (auto statement: statements) { for (auto statement: statements) {
KJ_IF_MAYBE(decl, parser.parseStatement(statement, parser.getParsers().fileLevelDecl)) { KJ_IF_MAYBE(decl, parser.parseStatement(statement, parser.getParsers().fileLevelDecl)) {
...@@ -64,14 +64,13 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result, ...@@ -64,14 +64,13 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result,
auto body = builder.getBody(); auto body = builder.getBody();
switch (body.which()) { switch (body.which()) {
case Declaration::Body::NAKED_ID: case Declaration::Body::NAKED_ID:
if (sawId) { if (fileDecl.getId().which() == Declaration::Id::UID) {
errorReporter.addError(builder.getStartByte(), builder.getEndByte(), errorReporter.addError(builder.getStartByte(), builder.getEndByte(),
kj::str("File can only have one ID.")); kj::str("File can only have one ID."));
} else { } else {
sawId = true; fileDecl.getId().adoptUid(body.disownNakedId());
result.setId(body.getNakedId());
if (builder.hasDocComment()) { if (builder.hasDocComment()) {
result.adoptDocComment(builder.disownDocComment()); fileDecl.adoptDocComment(builder.disownDocComment());
} }
} }
break; break;
...@@ -85,18 +84,20 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result, ...@@ -85,18 +84,20 @@ void parseFile(List<Statement>::Reader statements, ParsedFile::Builder result,
} }
} }
if (!sawId) { if (fileDecl.getId().which() != Declaration::Id::UID) {
uint64_t id = randomId();
fileDecl.getId().initUid().setValue(id);
errorReporter.addError(0, 0, errorReporter.addError(0, 0,
kj::str("File does not declare an ID. I've generated one for you. Add this line to your " kj::str("File does not declare an ID. I've generated one for you. Add this line to your "
"file: @0x", kj::hex(randomId() | (1ull << 63)), ";")); "file: @0x", kj::hex(id), ";"));
} }
auto declsBuilder = result.initTopDecls(decls.size()); auto declsBuilder = fileDecl.initNestedDecls(decls.size());
for (size_t i = 0; i < decls.size(); i++) { for (size_t i = 0; i < decls.size(); i++) {
declsBuilder.adoptWithCaveats(i, kj::mv(decls[i])); declsBuilder.adoptWithCaveats(i, kj::mv(decls[i]));
} }
auto annotationsBuilder = result.initAnnotations(annotations.size()); auto annotationsBuilder = fileDecl.initAnnotations(annotations.size());
for (size_t i = 0; i < annotations.size(); i++) { for (size_t i = 0; i < annotations.size(); i++) {
annotationsBuilder.adoptWithCaveats(i, kj::mv(annotations[i])); annotationsBuilder.adoptWithCaveats(i, kj::mv(annotations[i]));
} }
...@@ -817,7 +818,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -817,7 +818,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
auto& nakedId = arena.copy(p::transform(parsers.uid, auto& nakedId = arena.copy(p::transform(parsers.uid,
[this](Orphan<LocatedInteger>&& value) -> DeclParserResult { [this](Orphan<LocatedInteger>&& value) -> DeclParserResult {
auto decl = orphanage.newOrphan<Declaration>(); auto decl = orphanage.newOrphan<Declaration>();
decl.get().getBody().setNakedId(value.get().getValue()); decl.get().getBody().adoptNakedId(kj::mv(value));
return DeclParserResult(kj::mv(decl)); return DeclParserResult(kj::mv(decl));
})); }));
......
...@@ -1578,6 +1578,10 @@ DynamicStruct::Builder Orphan<DynamicStruct>::get() { ...@@ -1578,6 +1578,10 @@ DynamicStruct::Builder Orphan<DynamicStruct>::get() {
return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema))); return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
} }
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}
DynamicList::Builder Orphan<DynamicList>::get() { DynamicList::Builder Orphan<DynamicList>::get() {
if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) { if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
return DynamicList::Builder( return DynamicList::Builder(
...@@ -1588,4 +1592,9 @@ DynamicList::Builder Orphan<DynamicList>::get() { ...@@ -1588,4 +1592,9 @@ DynamicList::Builder Orphan<DynamicList>::get() {
} }
} }
DynamicList::Reader Orphan<DynamicList>::getReader() const {
return DynamicList::Reader(
schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}
} // namespace capnp } // namespace capnp
...@@ -306,6 +306,7 @@ private: ...@@ -306,6 +306,7 @@ private:
friend kj::String _::structString( friend kj::String _::structString(
_::StructReader reader, const _::RawSchema& schema); _::StructReader reader, const _::RawSchema& schema);
friend class Orphanage; friend class Orphanage;
friend class Orphan<DynamicStruct>;
}; };
class DynamicStruct::Builder { class DynamicStruct::Builder {
...@@ -456,6 +457,7 @@ private: ...@@ -456,6 +457,7 @@ private:
template <typename T, ::capnp::Kind k> template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class Orphanage; friend class Orphanage;
friend class Orphan<DynamicList>;
}; };
class DynamicList::Builder { class DynamicList::Builder {
...@@ -685,6 +687,7 @@ public: ...@@ -685,6 +687,7 @@ public:
Orphan& operator=(Orphan&&) = default; Orphan& operator=(Orphan&&) = default;
DynamicStruct::Builder get(); DynamicStruct::Builder get();
DynamicStruct::Reader getReader() const;
inline bool operator==(decltype(nullptr)) { return builder == nullptr; } inline bool operator==(decltype(nullptr)) { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) { return builder == nullptr; } inline bool operator!=(decltype(nullptr)) { return builder == nullptr; }
...@@ -711,6 +714,7 @@ public: ...@@ -711,6 +714,7 @@ public:
Orphan& operator=(Orphan&&) = default; Orphan& operator=(Orphan&&) = default;
DynamicList::Builder get(); DynamicList::Builder get();
DynamicList::Reader getReader() const;
inline bool operator==(decltype(nullptr)) { return builder == nullptr; } inline bool operator==(decltype(nullptr)) { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) { return builder == nullptr; } inline bool operator!=(decltype(nullptr)) { return builder == nullptr; }
......
...@@ -192,6 +192,15 @@ static_assert(POINTERS * BYTES_PER_POINTER / BYTES == sizeof(WirePointer), ...@@ -192,6 +192,15 @@ static_assert(POINTERS * BYTES_PER_POINTER / BYTES == sizeof(WirePointer),
static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(WirePointer), static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(WirePointer),
"BITS_PER_POINTER is wrong."); "BITS_PER_POINTER is wrong.");
namespace {
static const union {
AlignedData<POINTER_SIZE_IN_WORDS / WORDS> word;
WirePointer pointer;
} zero = {{{0}}};
} // namespace
// ======================================================================================= // =======================================================================================
struct WireHelpers { struct WireHelpers {
...@@ -285,10 +294,9 @@ struct WireHelpers { ...@@ -285,10 +294,9 @@ struct WireHelpers {
} }
} }
static KJ_ALWAYS_INLINE( static KJ_ALWAYS_INLINE(const word* followFars(
const word* followFars(const WirePointer*& ref, SegmentReader*& segment)) { const WirePointer*& ref, const word* refTarget, SegmentReader*& segment)) {
// Like the other followFars() but operates on readers. There is no `refTarget` parameter // Like the other followFars() but operates on readers.
// because `ref->target()` is valid for all use cases of this method.
// If the segment is null, this is an unchecked message, so there are no FAR pointers. // If the segment is null, this is an unchecked message, so there are no FAR pointers.
if (segment != nullptr && ref->kind() == WirePointer::FAR) { if (segment != nullptr && ref->kind() == WirePointer::FAR) {
...@@ -325,7 +333,7 @@ struct WireHelpers { ...@@ -325,7 +333,7 @@ struct WireHelpers {
return segment->getStartPtr() + pad->farPositionInSegment(); return segment->getStartPtr() + pad->farPositionInSegment();
} else { } else {
return ref->target(); return refTarget;
} }
} }
...@@ -466,7 +474,7 @@ struct WireHelpers { ...@@ -466,7 +474,7 @@ struct WireHelpers {
} }
--nestingLimit; --nestingLimit;
const word* ptr = followFars(ref, segment); const word* ptr = followFars(ref, ref->target(), segment);
WordCount64 result = 0 * WORDS; WordCount64 result = 0 * WORDS;
...@@ -1559,6 +1567,12 @@ struct WireHelpers { ...@@ -1559,6 +1567,12 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(StructReader readStructPointer( static KJ_ALWAYS_INLINE(StructReader readStructPointer(
SegmentReader* segment, const WirePointer* ref, const word* defaultValue, SegmentReader* segment, const WirePointer* ref, const word* defaultValue,
int nestingLimit)) { int nestingLimit)) {
return readStructPointer(segment, ref, ref->target(), defaultValue, nestingLimit);
}
static KJ_ALWAYS_INLINE(StructReader readStructPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget,
const word* defaultValue, int nestingLimit)) {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
if (defaultValue == nullptr || if (defaultValue == nullptr ||
...@@ -1567,6 +1581,7 @@ struct WireHelpers { ...@@ -1567,6 +1581,7 @@ struct WireHelpers {
} }
segment = nullptr; segment = nullptr;
ref = reinterpret_cast<const WirePointer*>(defaultValue); ref = reinterpret_cast<const WirePointer*>(defaultValue);
refTarget = ref->target();
defaultValue = nullptr; // If the default value is itself invalid, don't use it again. defaultValue = nullptr; // If the default value is itself invalid, don't use it again.
} }
...@@ -1575,7 +1590,7 @@ struct WireHelpers { ...@@ -1575,7 +1590,7 @@ struct WireHelpers {
goto useDefault; goto useDefault;
} }
const word* ptr = followFars(ref, segment); const word* ptr = followFars(ref, refTarget, segment);
if (KJ_UNLIKELY(ptr == nullptr)) { if (KJ_UNLIKELY(ptr == nullptr)) {
// Already reported the error. // Already reported the error.
goto useDefault; goto useDefault;
...@@ -1601,6 +1616,13 @@ struct WireHelpers { ...@@ -1601,6 +1616,13 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(ListReader readListPointer( static KJ_ALWAYS_INLINE(ListReader readListPointer(
SegmentReader* segment, const WirePointer* ref, const word* defaultValue, SegmentReader* segment, const WirePointer* ref, const word* defaultValue,
FieldSize expectedElementSize, int nestingLimit)) { FieldSize expectedElementSize, int nestingLimit)) {
return readListPointer(segment, ref, ref->target(), defaultValue,
expectedElementSize, nestingLimit);
}
static KJ_ALWAYS_INLINE(ListReader readListPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget,
const word* defaultValue, FieldSize expectedElementSize, int nestingLimit)) {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
if (defaultValue == nullptr || if (defaultValue == nullptr ||
...@@ -1609,6 +1631,7 @@ struct WireHelpers { ...@@ -1609,6 +1631,7 @@ struct WireHelpers {
} }
segment = nullptr; segment = nullptr;
ref = reinterpret_cast<const WirePointer*>(defaultValue); ref = reinterpret_cast<const WirePointer*>(defaultValue);
refTarget = ref->target();
defaultValue = nullptr; // If the default value is itself invalid, don't use it again. defaultValue = nullptr; // If the default value is itself invalid, don't use it again.
} }
...@@ -1617,7 +1640,7 @@ struct WireHelpers { ...@@ -1617,7 +1640,7 @@ struct WireHelpers {
goto useDefault; goto useDefault;
} }
const word* ptr = followFars(ref, segment); const word* ptr = followFars(ref, refTarget, segment);
if (KJ_UNLIKELY(ptr == nullptr)) { if (KJ_UNLIKELY(ptr == nullptr)) {
// Already reported error. // Already reported error.
goto useDefault; goto useDefault;
...@@ -1743,12 +1766,18 @@ struct WireHelpers { ...@@ -1743,12 +1766,18 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(Text::Reader readTextPointer( static KJ_ALWAYS_INLINE(Text::Reader readTextPointer(
SegmentReader* segment, const WirePointer* ref, SegmentReader* segment, const WirePointer* ref,
const void* defaultValue, ByteCount defaultSize)) { const void* defaultValue, ByteCount defaultSize)) {
return readTextPointer(segment, ref, ref->target(), defaultValue, defaultSize);
}
static KJ_ALWAYS_INLINE(Text::Reader readTextPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget,
const void* defaultValue, ByteCount defaultSize)) {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
if (defaultValue == nullptr) defaultValue = ""; if (defaultValue == nullptr) defaultValue = "";
return Text::Reader(reinterpret_cast<const char*>(defaultValue), defaultSize / BYTES); return Text::Reader(reinterpret_cast<const char*>(defaultValue), defaultSize / BYTES);
} else { } else {
const word* ptr = followFars(ref, segment); const word* ptr = followFars(ref, refTarget, segment);
if (KJ_UNLIKELY(ptr == nullptr)) { if (KJ_UNLIKELY(ptr == nullptr)) {
// Already reported error. // Already reported error.
...@@ -1791,11 +1820,17 @@ struct WireHelpers { ...@@ -1791,11 +1820,17 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(Data::Reader readDataPointer( static KJ_ALWAYS_INLINE(Data::Reader readDataPointer(
SegmentReader* segment, const WirePointer* ref, SegmentReader* segment, const WirePointer* ref,
const void* defaultValue, ByteCount defaultSize)) { const void* defaultValue, ByteCount defaultSize)) {
return readDataPointer(segment, ref, ref->target(), defaultValue, defaultSize);
}
static KJ_ALWAYS_INLINE(Data::Reader readDataPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget,
const void* defaultValue, ByteCount defaultSize)) {
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
useDefault: useDefault:
return Data::Reader(reinterpret_cast<const byte*>(defaultValue), defaultSize / BYTES); return Data::Reader(reinterpret_cast<const byte*>(defaultValue), defaultSize / BYTES);
} else { } else {
const word* ptr = followFars(ref, segment); const word* ptr = followFars(ref, refTarget, segment);
if (KJ_UNLIKELY(ptr == nullptr)) { if (KJ_UNLIKELY(ptr == nullptr)) {
// Already reported error. // Already reported error.
...@@ -1827,6 +1862,12 @@ struct WireHelpers { ...@@ -1827,6 +1862,12 @@ struct WireHelpers {
static ObjectReader readObjectPointer( static ObjectReader readObjectPointer(
SegmentReader* segment, const WirePointer* ref, SegmentReader* segment, const WirePointer* ref,
const word* defaultValue, int nestingLimit) { const word* defaultValue, int nestingLimit) {
return readObjectPointer(segment, ref, ref->target(), defaultValue, nestingLimit);
}
static ObjectReader readObjectPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget,
const word* defaultValue, int nestingLimit) {
// We can't really reuse readStructPointer() and readListPointer() because they are designed // We can't really reuse readStructPointer() and readListPointer() because they are designed
// for the case where we are expecting a specific type, and they do validation around that, // for the case where we are expecting a specific type, and they do validation around that,
// whereas this method is for the case where we accept any pointer. // whereas this method is for the case where we accept any pointer.
...@@ -1842,10 +1883,11 @@ struct WireHelpers { ...@@ -1842,10 +1883,11 @@ struct WireHelpers {
} }
segment = nullptr; segment = nullptr;
ref = reinterpret_cast<const WirePointer*>(defaultValue); ref = reinterpret_cast<const WirePointer*>(defaultValue);
refTarget = ref->target();
defaultValue = nullptr; // If the default value is itself invalid, don't use it again. defaultValue = nullptr; // If the default value is itself invalid, don't use it again.
} }
const word* ptr = WireHelpers::followFars(ref, segment); const word* ptr = WireHelpers::followFars(ref, refTarget, segment);
if (KJ_UNLIKELY(ptr == nullptr)) { if (KJ_UNLIKELY(ptr == nullptr)) {
// Already reported the error. // Already reported the error.
goto useDefault; goto useDefault;
...@@ -2111,13 +2153,13 @@ StructReader StructReader::readRoot( ...@@ -2111,13 +2153,13 @@ StructReader StructReader::readRoot(
StructReader StructReader::getStructField( StructReader StructReader::getStructField(
WirePointerCount ptrIndex, const word* defaultValue) const { WirePointerCount ptrIndex, const word* defaultValue) const {
const WirePointer* ref = ptrIndex >= pointerCount ? nullptr : pointers + ptrIndex; const WirePointer* ref = ptrIndex >= pointerCount ? &zero.pointer : pointers + ptrIndex;
return WireHelpers::readStructPointer(segment, ref, defaultValue, nestingLimit); return WireHelpers::readStructPointer(segment, ref, defaultValue, nestingLimit);
} }
ListReader StructReader::getListField( ListReader StructReader::getListField(
WirePointerCount ptrIndex, FieldSize expectedElementSize, const word* defaultValue) const { WirePointerCount ptrIndex, FieldSize expectedElementSize, const word* defaultValue) const {
const WirePointer* ref = ptrIndex >= pointerCount ? nullptr : pointers + ptrIndex; const WirePointer* ref = ptrIndex >= pointerCount ? &zero.pointer : pointers + ptrIndex;
return WireHelpers::readListPointer( return WireHelpers::readListPointer(
segment, ref, defaultValue, expectedElementSize, nestingLimit); segment, ref, defaultValue, expectedElementSize, nestingLimit);
} }
...@@ -2125,14 +2167,14 @@ ListReader StructReader::getListField( ...@@ -2125,14 +2167,14 @@ ListReader StructReader::getListField(
template <> template <>
Text::Reader StructReader::getBlobField<Text>( Text::Reader StructReader::getBlobField<Text>(
WirePointerCount ptrIndex, const void* defaultValue, ByteCount defaultSize) const { WirePointerCount ptrIndex, const void* defaultValue, ByteCount defaultSize) const {
const WirePointer* ref = ptrIndex >= pointerCount ? nullptr : pointers + ptrIndex; const WirePointer* ref = ptrIndex >= pointerCount ? &zero.pointer : pointers + ptrIndex;
return WireHelpers::readTextPointer(segment, ref, defaultValue, defaultSize); return WireHelpers::readTextPointer(segment, ref, defaultValue, defaultSize);
} }
template <> template <>
Data::Reader StructReader::getBlobField<Data>( Data::Reader StructReader::getBlobField<Data>(
WirePointerCount ptrIndex, const void* defaultValue, ByteCount defaultSize) const { WirePointerCount ptrIndex, const void* defaultValue, ByteCount defaultSize) const {
const WirePointer* ref = ptrIndex >= pointerCount ? nullptr : pointers + ptrIndex; const WirePointer* ref = ptrIndex >= pointerCount ? &zero.pointer : pointers + ptrIndex;
return WireHelpers::readDataPointer(segment, ref, defaultValue, defaultSize); return WireHelpers::readDataPointer(segment, ref, defaultValue, defaultSize);
} }
...@@ -2607,6 +2649,29 @@ ObjectBuilder OrphanBuilder::asObject() { ...@@ -2607,6 +2649,29 @@ ObjectBuilder OrphanBuilder::asObject() {
return result; return result;
} }
StructReader OrphanBuilder::asStructReader(StructSize size) const {
return WireHelpers::readStructPointer(
segment, tagAsPtr(), location, nullptr, std::numeric_limits<int>::max());
}
ListReader OrphanBuilder::asListReader(FieldSize elementSize) const {
return WireHelpers::readListPointer(
segment, tagAsPtr(), location, nullptr, elementSize, std::numeric_limits<int>::max());
}
Text::Reader OrphanBuilder::asTextReader() const {
return WireHelpers::readTextPointer(segment, tagAsPtr(), location, nullptr, 0 * BYTES);
}
Data::Reader OrphanBuilder::asDataReader() const {
return WireHelpers::readDataPointer(segment, tagAsPtr(), location, nullptr, 0 * BYTES);
}
ObjectReader OrphanBuilder::asObjectReader() const {
return WireHelpers::readObjectPointer(
segment, tagAsPtr(), location, nullptr, std::numeric_limits<int>::max());
}
void OrphanBuilder::euthanize() { void OrphanBuilder::euthanize() {
WireHelpers::zeroObject(segment, reinterpret_cast<WirePointer*>(&tag), location); WireHelpers::zeroObject(segment, reinterpret_cast<WirePointer*>(&tag), location);
memset(&tag, 0, sizeof(tag)); // Use memset to comply with aliasing rules. memset(&tag, 0, sizeof(tag)); // Use memset to comply with aliasing rules.
......
...@@ -758,6 +758,12 @@ public: ...@@ -758,6 +758,12 @@ public:
ObjectBuilder asObject(); ObjectBuilder asObject();
// Interpret as an arbitrary object. // Interpret as an arbitrary object.
StructReader asStructReader(StructSize size) const;
ListReader asListReader(FieldSize elementSize) const;
Text::Reader asTextReader() const;
Data::Reader asDataReader() const;
ObjectReader asObjectReader() const;
private: private:
static_assert(1 * POINTERS * WORDS_PER_POINTER == 1 * WORDS, static_assert(1 * POINTERS * WORDS_PER_POINTER == 1 * WORDS,
"This struct assumes a pointer is one word."); "This struct assumes a pointer is one word.");
...@@ -783,6 +789,7 @@ private: ...@@ -783,6 +789,7 @@ private:
} }
inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); } inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); }
inline const WirePointer* tagAsPtr() const { return reinterpret_cast<const WirePointer*>(&tag); }
void euthanize(); void euthanize();
// Erase the target object, zeroing it out and possibly reclaiming the memory. Called when // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when
......
...@@ -40,7 +40,8 @@ TEST(Orphans, Structs) { ...@@ -40,7 +40,8 @@ TEST(Orphans, Structs) {
Orphan<TestAllTypes> orphan = root.disownStructField(); Orphan<TestAllTypes> orphan = root.disownStructField();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
checkTestMessage(orphan.get().asReader()); checkTestMessage(orphan.getReader());
checkTestMessage(orphan.get());
EXPECT_FALSE(root.hasStructField()); EXPECT_FALSE(root.hasStructField());
root.adoptStructField(kj::mv(orphan)); root.adoptStructField(kj::mv(orphan));
...@@ -59,7 +60,8 @@ TEST(Orphans, Lists) { ...@@ -59,7 +60,8 @@ TEST(Orphans, Lists) {
Orphan<List<uint32_t>> orphan = root.disownUInt32List(); Orphan<List<uint32_t>> orphan = root.disownUInt32List();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
checkList(orphan.get().asReader(), {12u, 34u, 56u}); checkList(orphan.getReader(), {12u, 34u, 56u});
checkList(orphan.get(), {12u, 34u, 56u});
EXPECT_FALSE(root.hasUInt32List()); EXPECT_FALSE(root.hasUInt32List());
root.adoptUInt32List(kj::mv(orphan)); root.adoptUInt32List(kj::mv(orphan));
...@@ -80,6 +82,9 @@ TEST(Orphans, StructLists) { ...@@ -80,6 +82,9 @@ TEST(Orphans, StructLists) {
Orphan<List<TestAllTypes>> orphan = root.disownStructList(); Orphan<List<TestAllTypes>> orphan = root.disownStructList();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
ASSERT_EQ(2u, orphan.getReader().size());
EXPECT_EQ("foo", orphan.getReader()[0].getTextField());
EXPECT_EQ("bar", orphan.getReader()[1].getTextField());
ASSERT_EQ(2u, orphan.get().size()); ASSERT_EQ(2u, orphan.get().size());
EXPECT_EQ("foo", orphan.get()[0].getTextField()); EXPECT_EQ("foo", orphan.get()[0].getTextField());
EXPECT_EQ("bar", orphan.get()[1].getTextField()); EXPECT_EQ("bar", orphan.get()[1].getTextField());
...@@ -103,6 +108,7 @@ TEST(Orphans, Text) { ...@@ -103,6 +108,7 @@ TEST(Orphans, Text) {
Orphan<Text> orphan = root.disownTextField(); Orphan<Text> orphan = root.disownTextField();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
EXPECT_EQ("foo", orphan.getReader());
EXPECT_EQ("foo", orphan.get()); EXPECT_EQ("foo", orphan.get());
EXPECT_FALSE(root.hasTextField()); EXPECT_FALSE(root.hasTextField());
...@@ -122,6 +128,7 @@ TEST(Orphans, Data) { ...@@ -122,6 +128,7 @@ TEST(Orphans, Data) {
Orphan<Data> orphan = root.disownDataField(); Orphan<Data> orphan = root.disownDataField();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
EXPECT_EQ(data("foo"), orphan.getReader());
EXPECT_EQ(data("foo"), orphan.get()); EXPECT_EQ(data("foo"), orphan.get());
EXPECT_FALSE(root.hasDataField()); EXPECT_FALSE(root.hasDataField());
...@@ -155,7 +162,7 @@ TEST(Orphans, OrphanageStruct) { ...@@ -155,7 +162,7 @@ TEST(Orphans, OrphanageStruct) {
Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>(); Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>();
initTestMessage(orphan.get()); initTestMessage(orphan.get());
checkTestMessage(orphan.get().asReader()); checkTestMessage(orphan.getReader());
auto root = builder.initRoot<TestAllTypes>(); auto root = builder.initRoot<TestAllTypes>();
root.adoptStructField(kj::mv(orphan)); root.adoptStructField(kj::mv(orphan));
...@@ -168,7 +175,7 @@ TEST(Orphans, OrphanageList) { ...@@ -168,7 +175,7 @@ TEST(Orphans, OrphanageList) {
orphan.get().set(0, 123); orphan.get().set(0, 123);
orphan.get().set(1, 456); orphan.get().set(1, 456);
List<uint32_t>::Reader reader = orphan.get().asReader(); List<uint32_t>::Reader reader = orphan.getReader();
ASSERT_EQ(2u, reader.size()); ASSERT_EQ(2u, reader.size());
EXPECT_EQ(123u, reader[0]); EXPECT_EQ(123u, reader[0]);
EXPECT_EQ(456u, reader[1]); EXPECT_EQ(456u, reader[1]);
...@@ -212,7 +219,7 @@ TEST(Orphans, OrphanageStructCopy) { ...@@ -212,7 +219,7 @@ TEST(Orphans, OrphanageStructCopy) {
initTestMessage(root1); initTestMessage(root1);
Orphan<TestAllTypes> orphan = builder2.getOrphanage().newOrphanCopy(root1.asReader()); Orphan<TestAllTypes> orphan = builder2.getOrphanage().newOrphanCopy(root1.asReader());
checkTestMessage(orphan.get().asReader()); checkTestMessage(orphan.getReader());
auto root2 = builder2.initRoot<TestAllTypes>(); auto root2 = builder2.initRoot<TestAllTypes>();
root2.adoptStructField(kj::mv(orphan)); root2.adoptStructField(kj::mv(orphan));
...@@ -227,7 +234,7 @@ TEST(Orphans, OrphanageListCopy) { ...@@ -227,7 +234,7 @@ TEST(Orphans, OrphanageListCopy) {
Orphan<List<uint32_t>> orphan = builder2.getOrphanage().newOrphanCopy( Orphan<List<uint32_t>> orphan = builder2.getOrphanage().newOrphanCopy(
root1.asReader().getUInt32List()); root1.asReader().getUInt32List());
checkList(orphan.get().asReader(), {12u, 34u, 56u}); checkList(orphan.getReader(), {12u, 34u, 56u});
auto root2 = builder2.initRoot<TestAllTypes>(); auto root2 = builder2.initRoot<TestAllTypes>();
root2.adoptUInt32List(kj::mv(orphan)); root2.adoptUInt32List(kj::mv(orphan));
...@@ -237,7 +244,7 @@ TEST(Orphans, OrphanageTextCopy) { ...@@ -237,7 +244,7 @@ TEST(Orphans, OrphanageTextCopy) {
MallocMessageBuilder builder; MallocMessageBuilder builder;
Orphan<Text> orphan = builder.getOrphanage().newOrphanCopy(Text::Reader("foobarba")); Orphan<Text> orphan = builder.getOrphanage().newOrphanCopy(Text::Reader("foobarba"));
EXPECT_EQ("foobarba", orphan.get().asReader()); EXPECT_EQ("foobarba", orphan.getReader());
auto root = builder.initRoot<TestAllTypes>(); auto root = builder.initRoot<TestAllTypes>();
root.adoptTextField(kj::mv(orphan)); root.adoptTextField(kj::mv(orphan));
...@@ -247,7 +254,7 @@ TEST(Orphans, OrphanageDataCopy) { ...@@ -247,7 +254,7 @@ TEST(Orphans, OrphanageDataCopy) {
MallocMessageBuilder builder; MallocMessageBuilder builder;
Orphan<Data> orphan = builder.getOrphanage().newOrphanCopy(data("foo")); Orphan<Data> orphan = builder.getOrphanage().newOrphanCopy(data("foo"));
EXPECT_EQ(data("foo"), orphan.get().asReader()); EXPECT_EQ(data("foo"), orphan.getReader());
auto root = builder.initRoot<TestAllTypes>(); auto root = builder.initRoot<TestAllTypes>();
root.adoptDataField(kj::mv(orphan)); root.adoptDataField(kj::mv(orphan));
...@@ -259,9 +266,9 @@ TEST(Orphans, ZeroOut) { ...@@ -259,9 +266,9 @@ TEST(Orphans, ZeroOut) {
{ {
Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>(); Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>();
orphanReader = orphan.get().asReader(); orphanReader = orphan.getReader();
initTestMessage(orphan.get()); initTestMessage(orphan.get());
checkTestMessage(orphan.get().asReader()); checkTestMessage(orphan.getReader());
} }
// Once the Orphan destructor is called, the message should be zero'd out. // Once the Orphan destructor is called, the message should be zero'd out.
...@@ -278,7 +285,7 @@ TEST(Orphans, StructObject) { ...@@ -278,7 +285,7 @@ TEST(Orphans, StructObject) {
Orphan<TestAllTypes> orphan = root.disownObjectField<TestAllTypes>(); Orphan<TestAllTypes> orphan = root.disownObjectField<TestAllTypes>();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
checkTestMessage(orphan.get().asReader()); checkTestMessage(orphan.getReader());
EXPECT_FALSE(root.hasObjectField()); EXPECT_FALSE(root.hasObjectField());
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -297,7 +304,7 @@ TEST(Orphans, ListObject) { ...@@ -297,7 +304,7 @@ TEST(Orphans, ListObject) {
Orphan<List<uint32_t>> orphan = root.disownObjectField<List<uint32_t>>(); Orphan<List<uint32_t>> orphan = root.disownObjectField<List<uint32_t>>();
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
checkList(orphan.get().asReader(), {12u, 34u, 56u}); checkList(orphan.getReader(), {12u, 34u, 56u});
EXPECT_FALSE(root.hasObjectField()); EXPECT_FALSE(root.hasObjectField());
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -318,7 +325,7 @@ TEST(Orphans, DynamicStruct) { ...@@ -318,7 +325,7 @@ TEST(Orphans, DynamicStruct) {
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
EXPECT_TRUE(orphan.get().getSchema() == Schema::from<TestAllTypes>()); EXPECT_TRUE(orphan.get().getSchema() == Schema::from<TestAllTypes>());
checkDynamicTestMessage(orphan.get().asReader()); checkDynamicTestMessage(orphan.getReader());
EXPECT_FALSE(root.hasObjectField()); EXPECT_FALSE(root.hasObjectField());
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -337,7 +344,7 @@ TEST(Orphans, DynamicList) { ...@@ -337,7 +344,7 @@ TEST(Orphans, DynamicList) {
Orphan<DynamicList> orphan = root.disownObjectField<DynamicList>(Schema::from<List<uint32_t>>()); Orphan<DynamicList> orphan = root.disownObjectField<DynamicList>(Schema::from<List<uint32_t>>());
EXPECT_FALSE(orphan == nullptr); EXPECT_FALSE(orphan == nullptr);
checkList<uint32_t>(orphan.get().asReader(), {12, 34, 56}); checkList<uint32_t>(orphan.getReader(), {12, 34, 56});
EXPECT_FALSE(root.hasObjectField()); EXPECT_FALSE(root.hasObjectField());
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -377,7 +384,7 @@ TEST(Orphans, OrphanageDynamicStruct) { ...@@ -377,7 +384,7 @@ TEST(Orphans, OrphanageDynamicStruct) {
Orphan<DynamicStruct> orphan = builder.getOrphanage().newOrphan(Schema::from<TestAllTypes>()); Orphan<DynamicStruct> orphan = builder.getOrphanage().newOrphan(Schema::from<TestAllTypes>());
initDynamicTestMessage(orphan.get()); initDynamicTestMessage(orphan.get());
checkDynamicTestMessage(orphan.get().asReader()); checkDynamicTestMessage(orphan.getReader());
auto root = builder.initRoot<test::TestObject>(); auto root = builder.initRoot<test::TestObject>();
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -391,7 +398,7 @@ TEST(Orphans, OrphanageDynamicList) { ...@@ -391,7 +398,7 @@ TEST(Orphans, OrphanageDynamicList) {
orphan.get().set(0, 123); orphan.get().set(0, 123);
orphan.get().set(1, 456); orphan.get().set(1, 456);
checkList<uint32_t>(orphan.get().asReader(), {123, 456}); checkList<uint32_t>(orphan.getReader(), {123, 456});
auto root = builder.initRoot<test::TestObject>(); auto root = builder.initRoot<test::TestObject>();
root.adoptObjectField(kj::mv(orphan)); root.adoptObjectField(kj::mv(orphan));
...@@ -407,7 +414,7 @@ TEST(Orphans, OrphanageDynamicStructCopy) { ...@@ -407,7 +414,7 @@ TEST(Orphans, OrphanageDynamicStructCopy) {
Orphan<DynamicStruct> orphan = builder2.getOrphanage().newOrphanCopy( Orphan<DynamicStruct> orphan = builder2.getOrphanage().newOrphanCopy(
root1.asReader().getObjectField<DynamicStruct>(Schema::from<TestAllTypes>())); root1.asReader().getObjectField<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(orphan.get().asReader()); checkDynamicTestMessage(orphan.getReader());
auto root2 = builder2.initRoot<test::TestObject>(); auto root2 = builder2.initRoot<test::TestObject>();
root2.adoptObjectField(kj::mv(orphan)); root2.adoptObjectField(kj::mv(orphan));
...@@ -423,7 +430,7 @@ TEST(Orphans, OrphanageDynamicListCopy) { ...@@ -423,7 +430,7 @@ TEST(Orphans, OrphanageDynamicListCopy) {
Orphan<DynamicList> orphan = builder2.getOrphanage().newOrphanCopy( Orphan<DynamicList> orphan = builder2.getOrphanage().newOrphanCopy(
root1.asReader().getObjectField<DynamicList>(Schema::from<List<uint32_t>>())); root1.asReader().getObjectField<DynamicList>(Schema::from<List<uint32_t>>()));
checkList<uint32_t>(orphan.get().asReader(), {12, 34, 56}); checkList<uint32_t>(orphan.getReader(), {12, 34, 56});
auto root2 = builder2.initRoot<test::TestObject>(); auto root2 = builder2.initRoot<test::TestObject>();
root2.adoptObjectField(kj::mv(orphan)); root2.adoptObjectField(kj::mv(orphan));
......
...@@ -53,6 +53,7 @@ public: ...@@ -53,6 +53,7 @@ public:
Orphan& operator=(Orphan&&) = default; Orphan& operator=(Orphan&&) = default;
inline typename T::Builder get(); inline typename T::Builder get();
inline typename T::Reader getReader() const;
inline bool operator==(decltype(nullptr)) { return builder == nullptr; } inline bool operator==(decltype(nullptr)) { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) { return builder == nullptr; } inline bool operator!=(decltype(nullptr)) { return builder == nullptr; }
...@@ -136,6 +137,9 @@ struct OrphanGetImpl<T, Kind::STRUCT> { ...@@ -136,6 +137,9 @@ struct OrphanGetImpl<T, Kind::STRUCT> {
static inline typename T::Builder apply(_::OrphanBuilder& builder) { static inline typename T::Builder apply(_::OrphanBuilder& builder) {
return typename T::Builder(builder.asStruct(_::structSize<T>())); return typename T::Builder(builder.asStruct(_::structSize<T>()));
} }
static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) {
return typename T::Reader(builder.asStructReader(_::structSize<T>()));
}
}; };
template <typename T, Kind k> template <typename T, Kind k>
...@@ -143,6 +147,9 @@ struct OrphanGetImpl<List<T, k>, Kind::LIST> { ...@@ -143,6 +147,9 @@ struct OrphanGetImpl<List<T, k>, Kind::LIST> {
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) { static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
return typename List<T>::Builder(builder.asList(_::ElementSizeForType<T>::value)); return typename List<T>::Builder(builder.asList(_::ElementSizeForType<T>::value));
} }
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
}
}; };
template <typename T> template <typename T>
...@@ -150,6 +157,9 @@ struct OrphanGetImpl<List<T, Kind::STRUCT>, Kind::LIST> { ...@@ -150,6 +157,9 @@ struct OrphanGetImpl<List<T, Kind::STRUCT>, Kind::LIST> {
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) { static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
return typename List<T>::Builder(builder.asStructList(_::structSize<T>())); return typename List<T>::Builder(builder.asStructList(_::structSize<T>()));
} }
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
}
}; };
template <> template <>
...@@ -157,6 +167,9 @@ struct OrphanGetImpl<Text, Kind::BLOB> { ...@@ -157,6 +167,9 @@ struct OrphanGetImpl<Text, Kind::BLOB> {
static inline Text::Builder apply(_::OrphanBuilder& builder) { static inline Text::Builder apply(_::OrphanBuilder& builder) {
return Text::Builder(builder.asText()); return Text::Builder(builder.asText());
} }
static inline Text::Reader applyReader(const _::OrphanBuilder& builder) {
return Text::Reader(builder.asTextReader());
}
}; };
template <> template <>
...@@ -164,6 +177,9 @@ struct OrphanGetImpl<Data, Kind::BLOB> { ...@@ -164,6 +177,9 @@ struct OrphanGetImpl<Data, Kind::BLOB> {
static inline Data::Builder apply(_::OrphanBuilder& builder) { static inline Data::Builder apply(_::OrphanBuilder& builder) {
return Data::Builder(builder.asData()); return Data::Builder(builder.asData());
} }
static inline Data::Reader applyReader(const _::OrphanBuilder& builder) {
return Data::Reader(builder.asDataReader());
}
}; };
} // namespace _ (private) } // namespace _ (private)
...@@ -173,6 +189,11 @@ inline typename T::Builder Orphan<T>::get() { ...@@ -173,6 +189,11 @@ inline typename T::Builder Orphan<T>::get() {
return _::OrphanGetImpl<T>::apply(builder); return _::OrphanGetImpl<T>::apply(builder);
} }
template <typename T>
inline typename T::Reader Orphan<T>::getReader() const {
return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T> template <typename T>
struct Orphanage::GetInnerBuilder<T, Kind::STRUCT> { struct Orphanage::GetInnerBuilder<T, Kind::STRUCT> {
static inline _::StructBuilder apply(typename T::Builder& t) { static inline _::StructBuilder apply(typename T::Builder& t) {
......
...@@ -271,6 +271,9 @@ class SpaceFor { ...@@ -271,6 +271,9 @@ class SpaceFor {
// returns an Own<T> which will take care of calling T's destructor later. // returns an Own<T> which will take care of calling T's destructor later.
public: public:
inline SpaceFor() {}
inline ~SpaceFor() {}
template <typename... Params> template <typename... Params>
Own<T> construct(Params&&... params) { Own<T> construct(Params&&... params) {
ctor(value, kj::fwd<Params>(params)...); ctor(value, kj::fwd<Params>(params)...);
......
...@@ -166,7 +166,7 @@ template <typename T> ...@@ -166,7 +166,7 @@ template <typename T>
class Lazy { class Lazy {
public: public:
template <typename Func> template <typename Func>
const T& get(Func&& init); const T& get(Func&& init) const;
// The first thread to call get() will invoke the given init function to construct the value. // The first thread to call get() will invoke the given init function to construct the value.
// Other threads will block until construction completes, then return the same value. // Other threads will block until construction completes, then return the same value.
// //
...@@ -221,7 +221,7 @@ private: ...@@ -221,7 +221,7 @@ private:
template <typename T> template <typename T>
template <typename Func> template <typename Func>
const T& Lazy<T>::get(Func&& init) { const T& Lazy<T>::get(Func&& init) const {
if (!once.isInitialized()) { if (!once.isInitialized()) {
InitImpl<Func> initImpl(*this, kj::fwd<Func>(init)); InitImpl<Func> initImpl(*this, kj::fwd<Func>(init));
once.runOnce(initImpl); once.runOnce(initImpl);
......
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