Commit c1f3e3ff authored by Kenton Varda's avatar Kenton Varda

Flesh out dynamic API for orphans.

parent 55e48fc4
This diff is collapsed.
This diff is collapsed.
......@@ -1619,10 +1619,14 @@ struct WireHelpers {
}
static OrphanBuilder disown(SegmentBuilder* segment, WirePointer* ref) {
OrphanBuilder result(ref, segment,
ref->kind() == WirePointer::FAR ? nullptr : ref->target());
memset(ref, 0, sizeof(*ref));
return result;
if (ref->isNull()) {
return OrphanBuilder();
} else {
OrphanBuilder result(ref, segment,
ref->kind() == WirePointer::FAR ? nullptr : ref->target());
memset(ref, 0, sizeof(*ref));
return result;
}
}
// -----------------------------------------------------------------
......@@ -2744,8 +2748,14 @@ ObjectReader OrphanBuilder::asObjectReader() const {
}
void OrphanBuilder::euthanize() {
WireHelpers::zeroObject(segment, reinterpret_cast<WirePointer*>(&tag), location);
memset(&tag, 0, sizeof(tag)); // Use memset to comply with aliasing rules.
auto ref = reinterpret_cast<WirePointer*>(&tag);
if (ref->kind() == WirePointer::FAR) {
WireHelpers::zeroObject(segment, ref);
} else {
WireHelpers::zeroObject(segment, reinterpret_cast<WirePointer*>(&tag), location);
}
memset(ref, 0, sizeof(*ref));
segment = nullptr;
location = nullptr;
}
......
......@@ -751,7 +751,7 @@ public:
inline OrphanBuilder(): segment(nullptr), location(nullptr) { memset(&tag, 0, sizeof(tag)); }
OrphanBuilder(const OrphanBuilder& other) = delete;
inline OrphanBuilder(OrphanBuilder&& other);
inline ~OrphanBuilder();
inline ~OrphanBuilder() noexcept(false);
static OrphanBuilder initStruct(BuilderArena* arena, StructSize size);
static OrphanBuilder initList(BuilderArena* arena, ElementCount elementCount,
......@@ -769,8 +769,8 @@ public:
OrphanBuilder& operator=(const OrphanBuilder& other) = delete;
inline OrphanBuilder& operator=(OrphanBuilder&& other);
inline bool operator==(decltype(nullptr)) { return location == nullptr; }
inline bool operator!=(decltype(nullptr)) { return location != nullptr; }
inline bool operator==(decltype(nullptr)) const { return segment == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return segment != nullptr; }
StructBuilder asStruct(StructSize size);
// Interpret as a struct, or throw an exception if not a struct.
......@@ -1041,7 +1041,7 @@ inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other)
other.location = nullptr;
}
inline OrphanBuilder::~OrphanBuilder() {
inline OrphanBuilder::~OrphanBuilder() noexcept(false) {
if (segment != nullptr) euthanize();
}
......
......@@ -437,6 +437,157 @@ TEST(Orphans, OrphanageDynamicListCopy) {
checkList(root2.getObjectField<List<uint32_t>>(), {12u, 34u, 56u});
}
TEST(Orphans, DynamicStructAs) {
MallocMessageBuilder builder;
auto root = builder.initRoot<test::TestObject>();
initTestMessage(root.initObjectField<TestAllTypes>());
EXPECT_TRUE(root.hasObjectField());
Orphan<DynamicValue> orphan =
root.disownObjectField<DynamicStruct>(Schema::from<TestAllTypes>());
EXPECT_FALSE(orphan == nullptr);
checkTestMessage(orphan.getReader().as<TestAllTypes>());
checkTestMessage(orphan.get().as<TestAllTypes>());
{
Orphan<DynamicStruct> structOrphan = orphan.releaseAs<DynamicStruct>();
EXPECT_TRUE(orphan == nullptr);
EXPECT_FALSE(structOrphan == nullptr);
checkDynamicTestMessage(structOrphan.getReader());
checkDynamicTestMessage(structOrphan.get());
checkTestMessage(structOrphan.getReader().as<TestAllTypes>());
checkTestMessage(structOrphan.get().as<TestAllTypes>());
{
Orphan<TestAllTypes> typedOrphan = structOrphan.releaseAs<TestAllTypes>();
EXPECT_TRUE(structOrphan == nullptr);
EXPECT_FALSE(typedOrphan == nullptr);
checkTestMessage(typedOrphan.getReader());
checkTestMessage(typedOrphan.get());
orphan = kj::mv(typedOrphan);
EXPECT_FALSE(orphan == nullptr);
EXPECT_TRUE(typedOrphan == nullptr);
}
}
{
Orphan<TestAllTypes> typedOrphan = orphan.releaseAs<TestAllTypes>();
checkTestMessage(typedOrphan.getReader());
checkTestMessage(typedOrphan.get());
}
}
TEST(Orphans, DynamicListAs) {
MallocMessageBuilder builder;
auto root = builder.initRoot<test::TestObject>();
root.setObjectField<List<uint32_t>>({12, 34, 56});
EXPECT_TRUE(root.hasObjectField());
Orphan<DynamicValue> orphan = root.disownObjectField<DynamicList>(Schema::from<List<uint32_t>>());
EXPECT_FALSE(orphan == nullptr);
checkList(orphan.getReader().as<List<uint32_t>>(), {12, 34, 56});
checkList(orphan.get().as<List<uint32_t>>(), {12, 34, 56});
{
Orphan<DynamicList> listOrphan = orphan.releaseAs<DynamicList>();
EXPECT_TRUE(orphan == nullptr);
EXPECT_FALSE(listOrphan == nullptr);
checkList<uint32_t>(listOrphan.getReader(), {12, 34, 56});
checkList<uint32_t>(listOrphan.get(), {12, 34, 56});
checkList(listOrphan.getReader().as<List<uint32_t>>(), {12, 34, 56});
checkList(listOrphan.get().as<List<uint32_t>>(), {12, 34, 56});
{
Orphan<List<uint32_t>> typedOrphan = listOrphan.releaseAs<List<uint32_t>>();
EXPECT_TRUE(listOrphan == nullptr);
EXPECT_FALSE(typedOrphan == nullptr);
checkList(typedOrphan.getReader(), {12, 34, 56});
checkList(typedOrphan.get(), {12, 34, 56});
orphan = kj::mv(typedOrphan);
EXPECT_FALSE(orphan == nullptr);
EXPECT_TRUE(typedOrphan == nullptr);
}
}
{
Orphan<List<uint32_t>> typedOrphan = orphan.releaseAs<List<uint32_t>>();
checkList(typedOrphan.getReader(), {12, 34, 56});
checkList(typedOrphan.get(), {12, 34, 56});
}
}
TEST(Orphans, DynamicObject) {
MallocMessageBuilder builder;
auto root = builder.initRoot<test::TestObject>();
initTestMessage(root.initObjectField<TestAllTypes>());
EXPECT_TRUE(root.hasObjectField());
Orphan<DynamicValue> orphan = root.disownObjectField<DynamicObject>();
EXPECT_FALSE(orphan == nullptr);
checkTestMessage(orphan.getReader().as<DynamicObject>().as<TestAllTypes>());
Orphan<DynamicObject> objectOrphan = orphan.releaseAs<DynamicObject>();
checkTestMessage(objectOrphan.getAs<TestAllTypes>());
checkDynamicTestMessage(objectOrphan.getAs(Schema::from<TestAllTypes>()));
}
TEST(Orphans, DynamicDisown) {
MallocMessageBuilder builder;
auto root = builder.initRoot<TestAllTypes>();
initTestMessage(root);
Orphan<TestAllTypes> dstOrphan =
Orphanage::getForMessageContaining(root).newOrphan<TestAllTypes>();
auto dst = dstOrphan.get();
DynamicStruct::Builder dynamic = root;
DynamicStruct::Builder dynamicDst = dst;
for (auto field: dynamic.getSchema().getFields()) {
dynamicDst.adopt(field, dynamic.disown(field));
}
checkTestMessageAllZero(root.asReader());
checkTestMessage(dst.asReader());
for (auto field: dynamic.getSchema().getFields()) {
dynamicDst.adopt(field, dynamic.disown(field));
}
checkTestMessageAllZero(root.asReader());
checkTestMessageAllZero(dst.asReader());
}
TEST(Orphans, DynamicDisownGroup) {
MallocMessageBuilder builder;
auto root = builder.initRoot<test::TestGroups>();
auto bar = root.initGroups().initBar();
bar.setCorge(123);
bar.setGrault("foo");
bar.setGarply(9876543210987ll);
Orphan<test::TestGroups> dstOrphan =
Orphanage::getForMessageContaining(root).newOrphan<test::TestGroups>();
auto dst = dstOrphan.get();
toDynamic(dst).adopt("groups", toDynamic(root).disown("groups"));
EXPECT_EQ(test::TestGroups::Groups::FOO, root.getGroups().which());
EXPECT_EQ(test::TestGroups::Groups::BAR, dst.getGroups().which());
auto newBar = dst.getGroups().getBar();
EXPECT_EQ(123, newBar.getCorge());
EXPECT_EQ("foo", newBar.getGrault());
EXPECT_EQ(9876543210987ll, newBar.getGarply());
}
TEST(Orphans, OrphanageFromBuilder) {
MallocMessageBuilder builder;
auto root = builder.initRoot<TestAllTypes>();
......@@ -619,6 +770,23 @@ TEST(Orphans, DataZerodAfterUse) {
EXPECT_EQ("foo", root.getTextField());
}
TEST(Orphans, FarPointer) {
MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE);
auto root = builder.initRoot<TestAllTypes>();
auto child = root.initStructField();
initTestMessage(child);
auto orphan = root.disownStructField();
EXPECT_FALSE(root.hasStructField());
EXPECT_TRUE(orphan != nullptr);
EXPECT_FALSE(orphan == nullptr);
KJ_DBG(orphan != nullptr, orphan == nullptr);
checkTestMessage(orphan.getReader());
checkTestMessage(orphan.get());
}
} // namespace
} // namespace _ (private)
} // namespace capnp
......@@ -55,8 +55,8 @@ public:
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)) const { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
private:
_::OrphanBuilder builder;
......@@ -67,6 +67,8 @@ private:
friend struct _::PointerHelpers;
template <typename, Kind>
friend struct List;
template <typename U>
friend class Orphan;
friend class Orphanage;
};
......
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