Commit d99c0b4c authored by Kenton Varda's avatar Kenton Varda

Remove DynamicObject. DynamicValue can now contain an ObjectPointer to represent object fields.

parent 2b643930
......@@ -1811,13 +1811,13 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
if (constValue.getType() == DynamicValue::OBJECT) {
// We need to assign an appropriate schema to this object.
DynamicObject::Reader objValue = constValue.as<DynamicObject>();
ObjectPointer::Reader objValue = constValue.as<ObjectPointer>();
auto constType = constReader.getType();
switch (constType.which()) {
case schema::Type::STRUCT:
KJ_IF_MAYBE(structSchema, resolver.resolveBootstrapSchema(
constType.getStruct().getTypeId())) {
constValue = objValue.as(structSchema->asStruct());
constValue = objValue.getAs<DynamicStruct>(structSchema->asStruct());
} else {
// The struct's schema is broken for reasons already reported.
return nullptr;
......@@ -1825,7 +1825,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
break;
case schema::Type::LIST:
KJ_IF_MAYBE(listSchema, makeListSchemaOf(constType.getList().getElementType())) {
constValue = objValue.as(*listSchema);
constValue = objValue.getAs<DynamicList>(*listSchema);
} else {
// The list's schema is broken for reasons already reported.
return nullptr;
......
......@@ -191,11 +191,14 @@ TEST(DynamicApi, DynamicGenericObjects) {
checkTestMessage(root.asReader().as<test::TestObject>().getObjectField().getAs<TestAllTypes>());
checkDynamicTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<TestAllTypes>()));
root.get("objectField").as<ObjectPointer>().asReader()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.getObject("objectField", Schema::from<TestAllTypes>()));
......@@ -218,13 +221,16 @@ TEST(DynamicApi, DynamicGenericObjects) {
}
checkList<uint32_t>(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<List<uint32_t>>()),
root.get("objectField").as<ObjectPointer>().asReader()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.getObject("objectField", Schema::from<List<uint32_t>>()),
......
......@@ -125,30 +125,6 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
// =======================================================================================
DynamicStruct::Reader DynamicObject::Reader::as(StructSchema schema) const {
if (reader.kind == _::ObjectKind::NULL_POINTER) {
return DynamicStruct::Reader(schema, _::StructReader());
}
KJ_REQUIRE(reader.kind == _::ObjectKind::STRUCT, "Object is not a struct.") {
// Return default struct.
return DynamicStruct::Reader(schema, _::StructReader());
}
return DynamicStruct::Reader(schema, reader.structReader);
}
DynamicList::Reader DynamicObject::Reader::as(ListSchema schema) const {
if (reader.kind == _::ObjectKind::NULL_POINTER) {
return DynamicList::Reader(schema, _::ListReader());
}
KJ_REQUIRE(reader.kind == _::ObjectKind::LIST, "Object is not a list.") {
// Return empty list.
return DynamicList::Reader(schema, _::ListReader());
}
return DynamicList::Reader(schema, reader.listReader);
}
// =======================================================================================
bool DynamicStruct::Reader::isSetInUnion(StructSchema::Field field) const {
auto proto = field.getProto();
if (proto.hasDiscriminantValue()) {
......@@ -257,18 +233,14 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
dval.getList().getAs<_::UncheckedMessage>()));
}
case schema::Type::STRUCT: {
case schema::Type::STRUCT:
return DynamicStruct::Reader(
field.getContainingStruct().getDependency(type.getStruct().getTypeId()).asStruct(),
reader.getPointerField(slot.getOffset() * POINTERS)
.getStruct(dval.getStruct().getAs<_::UncheckedMessage>()));
}
case schema::Type::OBJECT: {
return DynamicObject::Reader(
reader.getPointerField(slot.getOffset() * POINTERS)
.getObject(dval.getObject().getAs<_::UncheckedMessage>()));
}
case schema::Type::OBJECT:
return ObjectPointer::Reader(reader.getPointerField(slot.getOffset() * POINTERS));
case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not yet implemented.");
......@@ -366,11 +338,8 @@ DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
dval.getStruct().getAs<_::UncheckedMessage>()));
}
case schema::Type::OBJECT: {
return DynamicObject::Builder(
builder.getPointerField(slot.getOffset() * POINTERS)
.getObject(dval.getObject().getAs<_::UncheckedMessage>()));
}
case schema::Type::OBJECT:
return ObjectPointer::Builder(builder.getPointerField(slot.getOffset() * POINTERS));
case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not yet implemented.");
......@@ -579,8 +548,8 @@ void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::
}
case schema::Type::OBJECT:
builder.getPointerField(slot.getOffset() * POINTERS)
.setObject(value.as<DynamicObject>().reader);
ObjectPointer::Builder(builder.getPointerField(slot.getOffset() * POINTERS))
.set(value.as<ObjectPointer>());
return;
case schema::Type::INTERFACE:
......@@ -1115,7 +1084,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
reader.getDataElement<uint16_t>(index * ELEMENTS));
case schema::Type::OBJECT:
return DynamicObject::Reader(reader.getPointerElement(index * ELEMENTS).getObject(nullptr));
return ObjectPointer::Reader(reader.getPointerElement(index * ELEMENTS));
case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not implemented.") {
......@@ -1480,7 +1449,7 @@ DynamicValue::Reader::Reader(ConstSchema constant) {
break;
case schema::Type::OBJECT:
*this = value.getObject().getAs<DynamicObject>();
*this = value.getObject();
break;
case schema::Type::INTERFACE:
......@@ -1620,7 +1589,7 @@ HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
HANDLE_TYPE(object, OBJECT, DynamicObject)
HANDLE_TYPE(object, OBJECT, ObjectPointer)
#undef HANDLE_TYPE
......@@ -1759,17 +1728,6 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
}
}
DynamicObject::Reader PointerHelpers<DynamicObject, Kind::UNKNOWN>::get(PointerReader reader) {
return DynamicObject::Reader(reader.getObject(nullptr));
}
DynamicObject::Builder PointerHelpers<DynamicObject, Kind::UNKNOWN>::get(PointerBuilder builder) {
return DynamicObject::Builder(builder.getObject(nullptr));
}
void PointerHelpers<DynamicObject, Kind::UNKNOWN>::set(
PointerBuilder builder, const DynamicObject::Reader& value) {
builder.setObject(value.reader);
}
} // namespace _ (private)
template <>
......@@ -1795,6 +1753,38 @@ void ObjectPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan)
}
}
template <>
DynamicStruct::Builder Orphan<ObjectPointer>::getAs<DynamicStruct>(StructSchema schema) {
return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}
template <>
DynamicStruct::Reader Orphan<ObjectPointer>::getAsReader<DynamicStruct>(StructSchema schema) const {
return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}
template <>
Orphan<DynamicStruct> Orphan<ObjectPointer>::releaseAs<DynamicStruct>(StructSchema schema) {
return Orphan<DynamicStruct>(schema, kj::mv(builder));
}
template <>
DynamicList::Builder Orphan<ObjectPointer>::getAs<DynamicList>(ListSchema schema) {
if (schema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(schema, builder.asStructList(
structSizeFromSchema(schema.getStructElementType())));
} else {
return DynamicList::Builder(schema, builder.asList(elementSizeFor(schema.whichElementType())));
}
}
template <>
DynamicList::Reader Orphan<ObjectPointer>::getAsReader<DynamicList>(ListSchema schema) const {
return DynamicList::Reader(schema, builder.asListReader(
elementSizeFor(schema.whichElementType())));
}
template <>
Orphan<DynamicList> Orphan<ObjectPointer>::releaseAs<DynamicList>(ListSchema schema) {
return Orphan<DynamicList>(schema, kj::mv(builder));
}
// -------------------------------------------------------------------
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
......@@ -1835,53 +1825,6 @@ DynamicList::Reader Orphan<DynamicList>::getReader() const {
schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}
DynamicObject::Builder Orphan<DynamicObject>::get() {
return DynamicObject::Builder(builder.asObject());
}
DynamicObject::Reader Orphan<DynamicObject>::getReader() const {
return DynamicObject::Reader(builder.asObjectReader());
}
DynamicStruct::Builder Orphan<DynamicObject>::getAs(StructSchema schema) {
return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}
DynamicList::Builder Orphan<DynamicObject>::getAs(ListSchema schema) {
if (schema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(schema,
builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
} else {
return DynamicList::Builder(schema,
builder.asList(elementSizeFor(schema.whichElementType())));
}
}
template <>
Text::Builder Orphan<DynamicObject>::getAs<Text>() {
return builder.asText();
}
template <>
Data::Builder Orphan<DynamicObject>::getAs<Data>() {
return builder.asData();
}
Orphan<DynamicStruct> Orphan<DynamicObject>::releaseAs(StructSchema schema) {
getAs(schema); // type check
return Orphan<DynamicStruct>(schema, kj::mv(builder));
}
Orphan<DynamicList> Orphan<DynamicObject>::releaseAs(ListSchema schema) {
getAs(schema); // type check
return Orphan<DynamicList>(schema, kj::mv(builder));
}
template <>
Orphan<Text> Orphan<DynamicObject>::releaseAs<Text>() {
getAs<Text>(); // type check
return Orphan<Text>(kj::mv(builder));
}
template <>
Orphan<Data> Orphan<DynamicObject>::releaseAs<Data>() {
getAs<Data>(); // type check
return Orphan<Data>(kj::mv(builder));
}
Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
: type(value.getType()), builder(kj::mv(builder)) {
switch (type) {
......@@ -1928,7 +1871,8 @@ DynamicValue::Builder Orphan<DynamicValue>::get() {
case DynamicValue::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not implemented.");
case DynamicValue::OBJECT:
return DynamicObject::Builder(builder.asObject());
KJ_FAIL_REQUIRE("Can't get() an untyped Object orphan; there is no underlying pointer to "
"wrap in an ObjectPointer::Builder.");
}
KJ_UNREACHABLE;
}
......@@ -1953,11 +1897,18 @@ DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
case DynamicValue::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not implemented.");
case DynamicValue::OBJECT:
return DynamicObject::Reader(builder.asObjectReader());
KJ_FAIL_ASSERT("Can't get() an untyped Object orphan; there is no underlying pointer to "
"wrap in an ObjectPointer::Builder.");
}
KJ_UNREACHABLE;
}
template <>
Orphan<ObjectPointer> Orphan<DynamicValue>::releaseAs<ObjectPointer>() {
KJ_REQUIRE(type == DynamicValue::OBJECT, "Value type mismatch.");
type = DynamicValue::UNKNOWN;
return Orphan<ObjectPointer>(kj::mv(builder));
}
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
......@@ -1971,20 +1922,6 @@ Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
return Orphan<DynamicList>(listSchema, kj::mv(builder));
}
template <>
Orphan<DynamicObject> Orphanage::newOrphanCopy<DynamicObject::Reader>(
const DynamicObject::Reader& copyFrom) const {
switch (copyFrom.reader.kind) {
case _::ObjectKind::NULL_POINTER:
return Orphan<DynamicObject>();
case _::ObjectKind::STRUCT:
return Orphan<DynamicObject>(_::OrphanBuilder::copy(arena, copyFrom.reader.structReader));
case _::ObjectKind::LIST:
return Orphan<DynamicObject>(_::OrphanBuilder::copy(arena, copyFrom.reader.listReader));
}
KJ_UNREACHABLE;
}
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
const DynamicValue::Reader& copyFrom) const {
......
......@@ -72,11 +72,6 @@ struct DynamicValue {
class Builder;
};
class DynamicEnum;
struct DynamicObject {
DynamicObject() = delete;
class Reader;
class Builder;
};
struct DynamicStruct {
DynamicStruct() = delete;
class Reader;
......@@ -147,68 +142,6 @@ private:
// -------------------------------------------------------------------
class DynamicObject::Reader {
// Represents an "Object" field of unknown type.
public:
typedef DynamicObject Reads;
Reader() = default;
template <typename T>
typename T::Reader as() const;
// Convert the object to the given struct, list, or blob type.
DynamicStruct::Reader as(StructSchema schema) const;
DynamicList::Reader as(ListSchema schema) const;
private:
_::ObjectReader reader;
inline Reader(_::ObjectReader reader): reader(reader) {}
friend struct DynamicStruct;
friend struct DynamicList;
template <typename T, Kind K>
friend struct _::PointerHelpers;
friend class DynamicObject::Builder;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
friend class Orphanage;
};
class DynamicObject::Builder: public kj::DisallowConstCopy {
// Represents an "Object" field of unknown type.
//
// You can't actually do anything with a DynamicObject::Builder except read it. It can't be
// converted to a Builder for any specific type because that could require initializing or
// updating the pointer that points *to* this object. Therefore, you must call
// DynamicStruct::Builder::{get,set,init}Object() and pass a type schema to build object fields.
public:
typedef DynamicObject Builds;
Builder() = default;
inline Builder(decltype(nullptr)) {}
Builder(Builder&) = default;
Builder(Builder&&) = default;
Reader asReader() const { return Reader(builder.asReader()); }
private:
_::ObjectBuilder builder;
inline Builder(_::ObjectBuilder builder): builder(builder) {}
friend struct DynamicStruct;
friend struct DynamicList;
template <typename T, Kind K>
friend struct _::PointerHelpers;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
};
// -------------------------------------------------------------------
class DynamicStruct::Reader {
public:
typedef DynamicStruct Reads;
......@@ -260,7 +193,6 @@ private:
template <typename T, Kind K>
friend struct _::PointerHelpers;
friend struct DynamicObject;
friend class DynamicStruct::Builder;
friend struct DynamicList;
friend class MessageReader;
......@@ -272,6 +204,7 @@ private:
friend class Orphanage;
friend class Orphan<DynamicStruct>;
friend class Orphan<DynamicValue>;
friend class Orphan<ObjectPointer>;
};
class DynamicStruct::Builder {
......@@ -380,8 +313,8 @@ private:
friend struct ::capnp::ToDynamic_;
friend class Orphanage;
friend class Orphan<DynamicStruct>;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
friend class Orphan<ObjectPointer>;
};
// -------------------------------------------------------------------
......@@ -418,13 +351,13 @@ private:
template <typename T, Kind k>
friend struct _::PointerHelpers;
friend struct DynamicStruct;
friend struct DynamicObject;
friend class DynamicList::Builder;
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class Orphanage;
friend class Orphan<DynamicList>;
friend class Orphan<DynamicValue>;
friend class Orphan<ObjectPointer>;
};
class DynamicList::Builder {
......@@ -474,19 +407,17 @@ private:
template <typename T, Kind k>
friend struct _::OrphanGetImpl;
friend class Orphan<DynamicList>;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
friend class Orphan<ObjectPointer>;
};
// -------------------------------------------------------------------
// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicObject, DynamicStruct, and
// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicStruct, and
// DynamicList, so that we can define DynamicValue::as().
template <> struct ReaderFor_ <DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct BuilderFor_<DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct ReaderFor_ <DynamicObject, Kind::UNKNOWN> { typedef DynamicObject::Reader Type; };
template <> struct BuilderFor_<DynamicObject, Kind::UNKNOWN> { typedef DynamicObject::Builder Type; };
template <> struct ReaderFor_ <DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Reader Type; };
template <> struct BuilderFor_<DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Builder Type; };
template <> struct ReaderFor_ <DynamicList, Kind::UNKNOWN> { typedef DynamicList::Reader Type; };
......@@ -518,7 +449,7 @@ public:
inline Reader(const DynamicList::Reader& value);
inline Reader(DynamicEnum value);
inline Reader(const DynamicStruct::Reader& value);
inline Reader(const DynamicObject::Reader& value);
inline Reader(const ObjectPointer::Reader& value);
Reader(ConstSchema constant);
template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
......@@ -528,9 +459,9 @@ public:
inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
// Use to interpret the value as some Cap'n Proto type. Allowed types are:
// - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value.
// - Text, Data, any struct type: Returns the corresponding Reader.
// - Text, Data, ObjectPointer, any struct type: Returns the corresponding Reader.
// - List<T> for any T listed above: Returns List<T>::Reader.
// - DynamicEnum, DynamicObject: Returns the corresponding type.
// - DynamicEnum: Returns the corresponding type.
// - DynamicStruct, DynamicList: Returns the corresponding Reader.
//
// DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
......@@ -563,7 +494,7 @@ private:
DynamicList::Reader listValue;
DynamicEnum enumValue;
DynamicStruct::Reader structValue;
DynamicObject::Reader objectValue;
ObjectPointer::Reader objectValue;
};
template <typename T, Kind kind = kind<T>()> struct AsImpl;
......@@ -598,7 +529,7 @@ public:
inline Builder(DynamicList::Builder value);
inline Builder(DynamicEnum value);
inline Builder(DynamicStruct::Builder value);
inline Builder(DynamicObject::Builder value);
inline Builder(ObjectPointer::Builder value);
template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
inline Builder(T value): Builder(toDynamic(value)) {}
......@@ -635,7 +566,7 @@ private:
DynamicList::Builder listValue;
DynamicEnum enumValue;
DynamicStruct::Builder structValue;
DynamicObject::Builder objectValue;
ObjectPointer::Builder objectValue;
};
template <typename T, Kind kind = kind<T>()> struct AsImpl;
......@@ -648,8 +579,6 @@ private:
kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value);
kj::StringTree KJ_STRINGIFY(DynamicEnum value);
kj::StringTree KJ_STRINGIFY(const DynamicObject::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicObject::Builder& value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value);
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value);
......@@ -689,8 +618,8 @@ private:
friend struct _::PointerHelpers;
friend struct DynamicList;
friend class Orphanage;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
friend class Orphan<ObjectPointer>;
friend class MessageBuilder;
};
......@@ -725,56 +654,8 @@ private:
friend struct _::PointerHelpers;
friend struct DynamicList;
friend class Orphanage;
friend class Orphan<DynamicObject>;
friend class Orphan<DynamicValue>;
};
template <>
class Orphan<DynamicObject> {
public:
Orphan() = default;
KJ_DISALLOW_COPY(Orphan);
Orphan(Orphan&&) = default;
Orphan& operator=(Orphan&&) = default;
DynamicObject::Builder get();
DynamicObject::Reader getReader() const;
template <typename T>
BuilderFor<T> getAs();
// Coerce the object to the given type and return a builder for that type. This may relocate
// the object if it was originally created with a previous version of the schema and the sizes
// don't match.
//
// Notice that DynamicObject::Builder does not have an "as<T>()" method, which is why this is
// needed.
template <typename T>
Orphan<T> releaseAs();
// Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
// the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
// transferred to the returned Orphan<T>.
DynamicStruct::Builder getAs(StructSchema schema);
DynamicList::Builder getAs(ListSchema schema);
// Dynamic versions of 'getAs()'.
Orphan<DynamicStruct> releaseAs(StructSchema schema);
Orphan<DynamicList> releaseAs(ListSchema schema);
// Dynamic versions of 'releaseAs()'.
inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
private:
_::OrphanBuilder builder;
explicit Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {}
template <typename, Kind>
friend struct _::PointerHelpers;
friend class Orphan<DynamicValue>;
friend class Orphanage;
friend class Orphan<ObjectPointer>;
};
template <>
......@@ -800,6 +681,7 @@ public:
Orphan(Orphan&&) = default;
template <typename T>
Orphan(Orphan<T>&&);
Orphan(Orphan<ObjectPointer>&&);
KJ_DISALLOW_COPY(Orphan);
Orphan& operator=(Orphan&&) = default;
......@@ -848,27 +730,12 @@ private:
};
template <typename T>
BuilderFor<T> Orphan<DynamicObject>::getAs() {
return getAs(Schema::from<T>()).template as<T>();
}
template <>
Text::Builder Orphan<DynamicObject>::getAs<Text>();
template <>
Data::Builder Orphan<DynamicObject>::getAs<Data>();
template <typename T>
Orphan<T> Orphan<DynamicObject>::releaseAs() {
return releaseAs(Schema::from<T>()).template releaseAs<T>();
}
template <>
Orphan<Text> Orphan<DynamicObject>::releaseAs<Text>();
template <>
Orphan<Data> Orphan<DynamicObject>::releaseAs<Data>();
template <typename T>
Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
: Orphan(other.get(), kj::mv(other.builder)) {}
inline Orphan<DynamicValue>::Orphan(Orphan<ObjectPointer>&& other)
: type(DynamicValue::OBJECT), builder(kj::mv(other.builder)) {}
template <typename T>
Orphan<T> Orphan<DynamicStruct>::releaseAs() {
get().as<T>(); // type check
......@@ -888,6 +755,8 @@ Orphan<T> Orphan<DynamicValue>::releaseAs() {
return Orphan<T>(kj::mv(builder));
}
template <>
Orphan<ObjectPointer> Orphan<DynamicValue>::releaseAs<ObjectPointer>();
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
......@@ -920,10 +789,6 @@ inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
return Orphan<DynamicList>(copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.reader));
}
template <>
Orphan<DynamicObject> Orphanage::newOrphanCopy<DynamicObject::Reader>(
const DynamicObject::Reader& copyFrom) const;
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
const DynamicValue::Reader& copyFrom) const;
......@@ -985,19 +850,6 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
}
};
template <>
struct PointerHelpers<DynamicObject, Kind::UNKNOWN> {
static DynamicObject::Reader get(PointerReader reader);
static DynamicObject::Builder get(PointerBuilder builder);
static void set(PointerBuilder builder, const DynamicObject::Reader& value);
static inline void adopt(PointerBuilder builder, Orphan<DynamicObject>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<DynamicObject> disown(PointerBuilder builder) {
return Orphan<DynamicObject>(builder.disown());
}
};
} // namespace _ (private)
template <typename T>
......@@ -1043,6 +895,19 @@ inline Orphan<T> ObjectPointer::Builder::disownAs(ListSchema schema) {
return _::PointerHelpers<T>::disown(builder, schema);
}
template <>
DynamicStruct::Builder Orphan<ObjectPointer>::getAs<DynamicStruct>(StructSchema schema);
template <>
DynamicList::Builder Orphan<ObjectPointer>::getAs<DynamicList>(ListSchema schema);
template <>
DynamicStruct::Reader Orphan<ObjectPointer>::getAsReader<DynamicStruct>(StructSchema schema) const;
template <>
DynamicList::Reader Orphan<ObjectPointer>::getAsReader<DynamicList>(ListSchema schema) const;
template <>
Orphan<DynamicStruct> Orphan<ObjectPointer>::releaseAs<DynamicStruct>(StructSchema schema);
template <>
Orphan<DynamicList> Orphan<ObjectPointer>::releaseAs<DynamicList>(ListSchema schema);
// =======================================================================================
// Inline implementation details.
......@@ -1118,7 +983,7 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(ObjectPointer, OBJECT, object);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
......@@ -1152,7 +1017,7 @@ CAPNP_DECLARE_TYPE(data, DATA, Data)
CAPNP_DECLARE_TYPE(list, LIST, DynamicList)
CAPNP_DECLARE_TYPE(struct, STRUCT, DynamicStruct)
CAPNP_DECLARE_TYPE(enum, ENUM, DynamicEnum)
CAPNP_DECLARE_TYPE(object, OBJECT, DynamicObject)
CAPNP_DECLARE_TYPE(object, OBJECT, ObjectPointer)
#undef CAPNP_DECLARE_TYPE
// CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the
......@@ -1207,13 +1072,6 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
// -------------------------------------------------------------------
template <typename T>
inline typename T::Reader DynamicObject::Reader::as() const {
return as(Schema::from<T>()).template as<T>();
}
// -------------------------------------------------------------------
template <typename T>
typename T::Reader DynamicStruct::Reader::as() const {
static_assert(kind<T>() == Kind::STRUCT,
......
......@@ -1617,19 +1617,19 @@ struct WireHelpers {
}
}
static KJ_ALWAYS_INLINE(void setObjectPointer(
SegmentBuilder* segment, WirePointer* ref, ObjectReader value)) {
static KJ_ALWAYS_INLINE(SegmentAnd<word*> setObjectPointer(
SegmentBuilder* segment, WirePointer* ref, ObjectReader value,
BuilderArena* orphanArena = nullptr)) {
switch (value.kind) {
case ObjectKind::NULL_POINTER:
memset(ref, 0, sizeof(*ref));
break;
return { segment, nullptr };
case ObjectKind::STRUCT:
setStructPointer(segment, ref, value.structReader);
break;
return setStructPointer(segment, ref, value.structReader, orphanArena);
case ObjectKind::LIST:
setListPointer(segment, ref, value.listReader);
break;
return setListPointer(segment, ref, value.listReader, orphanArena);
}
KJ_UNREACHABLE;
}
static void adopt(SegmentBuilder* segment, WirePointer* ref, OrphanBuilder&& value) {
......@@ -2139,7 +2139,7 @@ void PointerBuilder::setList(const ListReader& value) {
}
void PointerBuilder::setObject(const ObjectReader& value) {
return WireHelpers::setObjectPointer(segment, pointer, value);
WireHelpers::setObjectPointer(segment, pointer, value);
}
void PointerBuilder::adopt(OrphanBuilder&& value) {
......@@ -2159,6 +2159,18 @@ bool PointerBuilder::isNull() {
return pointer->isNull();
}
void PointerBuilder::transferFrom(PointerBuilder other) {
WireHelpers::transferPointer(segment, pointer, other.segment, other.pointer);
}
void PointerBuilder::copyFrom(PointerReader other) {
WireHelpers::setObjectPointer(segment, pointer, other.getObject(nullptr));
}
PointerReader PointerBuilder::asReader() const {
return PointerReader(segment, pointer, std::numeric_limits<int>::max());
}
// =======================================================================================
// PointerReader
......@@ -2541,6 +2553,15 @@ OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, ListReader copyFrom) {
return result;
}
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, PointerReader copyFrom) {
OrphanBuilder result;
auto allocation = WireHelpers::setObjectPointer(
nullptr, result.tagAsPtr(), copyFrom.getObject(nullptr), arena);
result.segment = allocation.segment;
result.location = reinterpret_cast<word*>(allocation.value);
return result;
}
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, Text::Reader copyFrom) {
OrphanBuilder result;
auto allocation = WireHelpers::setTextPointer(
......
......@@ -316,6 +316,8 @@ public:
void copyFrom(PointerReader other);
// Equivalent to `set(other.get())`.
PointerReader asReader() const;
private:
SegmentBuilder* segment; // Memory segment in which the pointer resides.
WirePointer* pointer; // Pointer to the pointer.
......@@ -360,6 +362,7 @@ private:
friend class StructReader;
friend class ListReader;
friend class PointerBuilder;
};
// -------------------------------------------------------------------
......@@ -739,6 +742,7 @@ public:
static OrphanBuilder copy(BuilderArena* arena, StructReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, ListReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, PointerReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, Text::Reader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, Data::Reader copyFrom);
......
......@@ -26,11 +26,13 @@
#include "layout.h"
#include "pointer-helpers.h"
#include "orphan.h"
namespace capnp {
class StructSchema;
class ListSchema;
class Orphanage;
struct ObjectPointer {
// Reader/Builder for the `Object` field type, i.e. a pointer that can point to an arbitrary
......@@ -38,6 +40,8 @@ struct ObjectPointer {
class Reader {
public:
typedef ObjectPointer Reads;
Reader() = default;
inline Reader(_::PointerReader reader): reader(reader) {}
......@@ -57,10 +61,14 @@ struct ObjectPointer {
private:
_::PointerReader reader;
friend struct ObjectPointer;
friend class Orphanage;
};
class Builder {
public:
typedef ObjectPointer Builds;
Builder() = delete;
inline Builder(decltype(nullptr)) {}
inline Builder(_::PointerBuilder builder): builder(builder) {}
......@@ -107,6 +115,9 @@ struct ObjectPointer {
inline void setAs(std::initializer_list<ReaderFor<ListElementType<T>>> list);
// Valid for T = List<?>.
inline void set(Reader value) { builder.copyFrom(value.reader); }
// Set to a copy of another ObjectPointer.
template <typename T>
inline void adopt(Orphan<T>&& orphan);
// Valid for T = any generated struct type, List<U>, Text, Data, DynamicList, DynamicStruct,
......@@ -124,11 +135,69 @@ struct ObjectPointer {
inline Orphan<T> disownAs(ListSchema schema);
// Only valid for T = DynamicList. Requires `#include <capnp/dynamic.h>`.
inline Orphan<ObjectPointer> disown();
// Disown without a type.
inline Reader asReader() const { return Reader(builder.asReader()); }
inline operator Reader() const { return Reader(builder.asReader()); }
private:
_::PointerBuilder builder;
};
};
template <>
class Orphan<ObjectPointer> {
// An orphaned object of unknown type.
public:
Orphan() = default;
KJ_DISALLOW_COPY(Orphan);
Orphan(Orphan&&) = default;
Orphan& operator=(Orphan&&) = default;
// It's not possible to get an ObjectPointer::{Reader,Builder} directly since there is no
// underlying pointer (the pointer would normally live in the parent, but this object is
// orphaned). It is possible, however, to request readers/builders.
template <typename T>
inline typename T::Builder getAs();
template <typename T>
inline typename T::Builder getAs(StructSchema schema);
template <typename T>
inline typename T::Builder getAs(ListSchema schema);
template <typename T>
inline typename T::Reader getAsReader() const;
template <typename T>
inline typename T::Reader getAsReader(StructSchema schema) const;
template <typename T>
inline typename T::Reader getAsReader(ListSchema schema) const;
template <typename T>
inline Orphan<T> releaseAs();
template <typename T>
inline Orphan<T> releaseAs(StructSchema schema);
template <typename T>
inline Orphan<T> releaseAs(ListSchema schema);
// Down-cast the orphan to a specific type.
inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
private:
_::OrphanBuilder builder;
inline Orphan(_::OrphanBuilder&& builder)
: builder(kj::mv(builder)) {}
template <typename, Kind>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U>
friend class Orphan;
friend class ObjectPointer::Builder;
};
// =======================================================================================
// Inline implementation details
......@@ -185,6 +254,33 @@ inline Orphan<T> ObjectPointer::Builder::disownAs() {
return _::PointerHelpers<T>::disown(builder);
}
inline Orphan<ObjectPointer> ObjectPointer::Builder::disown() {
return Orphan<ObjectPointer>(builder.disown());
}
template <> struct ReaderFor_ <ObjectPointer, Kind::UNKNOWN> { typedef ObjectPointer::Reader Type; };
template <> struct BuilderFor_<ObjectPointer, Kind::UNKNOWN> { typedef ObjectPointer::Builder Type; };
template <>
struct Orphanage::GetInnerReader<ObjectPointer, Kind::UNKNOWN> {
static inline _::PointerReader apply(const ObjectPointer::Reader& t) {
return t.reader;
}
};
template <typename T>
inline typename T::Builder Orphan<ObjectPointer>::getAs() {
return _::OrphanGetImpl<T>::apply(builder);
}
template <typename T>
inline typename T::Reader Orphan<ObjectPointer>::getAsReader() const {
return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T>
inline Orphan<T> Orphan<ObjectPointer>::releaseAs() {
return Orphan<T>(kj::mv(builder));
}
} // namespace capnp
#endif // CAPNP_OBJECT_H_
......@@ -529,14 +529,12 @@ TEST(Orphans, DynamicObject) {
initTestMessage(root.getObjectField().initAs<TestAllTypes>());
EXPECT_TRUE(root.hasObjectField());
Orphan<DynamicValue> orphan = root.getObjectField().disownAs<DynamicObject>();
Orphan<DynamicValue> orphan = root.getObjectField().disown();
EXPECT_EQ(DynamicValue::OBJECT, orphan.getType());
checkTestMessage(orphan.getReader().as<DynamicObject>().as<TestAllTypes>());
Orphan<DynamicObject> objectOrphan = orphan.releaseAs<DynamicObject>();
Orphan<ObjectPointer> objectOrphan = orphan.releaseAs<ObjectPointer>();
checkTestMessage(objectOrphan.getAs<TestAllTypes>());
checkDynamicTestMessage(objectOrphan.getAs(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(objectOrphan.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
}
TEST(Orphans, DynamicDisown) {
......
......@@ -267,8 +267,6 @@ kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(valu
kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(DynamicEnum value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value) { return stringify(value); }
......
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