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