Commit fff8e987 authored by Kenton Varda's avatar Kenton Varda

Merge branch 'master' of github.com:kentonv/capnproto

parents 6b35c286 bd763a00
...@@ -106,6 +106,80 @@ TEST(Any, AnyPointer) { ...@@ -106,6 +106,80 @@ TEST(Any, AnyPointer) {
} }
} }
TEST(Any, AnyStruct) {
MallocMessageBuilder builder;
auto root = builder.getRoot<test::TestAnyPointer>();
initTestMessage(root.getAnyPointerField().initAs<TestAllTypes>());
checkTestMessage(root.getAnyPointerField().getAs<TestAllTypes>());
checkTestMessage(root.asReader().getAnyPointerField().getAs<TestAllTypes>());
EXPECT_EQ(48, root.getAnyPointerField().getAs<AnyStruct>().getDataSection().size());
EXPECT_EQ(20, root.getAnyPointerField().getAs<AnyStruct>().getPointerSection().size());
EXPECT_EQ(48, root.getAnyPointerField().asReader().getAs<AnyStruct>().getDataSection().size());
EXPECT_EQ(20, root.getAnyPointerField().asReader().getAs<AnyStruct>().getPointerSection().size());
auto b = toAny(root.getAnyPointerField().getAs<TestAllTypes>());
EXPECT_EQ(48, b.getDataSection().size());
EXPECT_EQ(20, b.getPointerSection().size());
auto r = toAny(root.getAnyPointerField().getAs<TestAllTypes>().asReader());
EXPECT_EQ(48, r.getDataSection().size());
EXPECT_EQ(20, r.getPointerSection().size());
r = toAny(root.getAnyPointerField().getAs<TestAllTypes>()).asReader();
EXPECT_EQ(48, r.getDataSection().size());
EXPECT_EQ(20, r.getPointerSection().size());
{
MallocMessageBuilder b2;
auto root2 = b2.getRoot<test::TestAnyPointer>();
auto sb = root2.getAnyPointerField().initAsAnyStruct(r.getDataSection().size() / 8, r.getPointerSection().size());
EXPECT_EQ(48, sb.getDataSection().size());
EXPECT_EQ(20, sb.getPointerSection().size());
// TODO: is there a higher-level API for this?
memcpy(sb.getDataSection().begin(), r.getDataSection().begin(), r.getDataSection().size());
}
}
TEST(Any, AnyList) {
MallocMessageBuilder builder;
auto root = builder.getRoot<test::TestAnyPointer>();
List<TestAllTypes>::Builder b = root.getAnyPointerField().initAs<List<TestAllTypes>>(2);
initTestMessage(b[0]);
auto ptr = root.getAnyPointerField().getAs<AnyList>();
EXPECT_EQ(2, ptr.size());
EXPECT_EQ(48, ptr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, ptr.as<List<AnyStruct>>()[0].getPointerSection().size());
auto readPtr = root.getAnyPointerField().asReader().getAs<AnyList>();
EXPECT_EQ(2, readPtr.size());
EXPECT_EQ(48, readPtr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, readPtr.as<List<AnyStruct>>()[0].getPointerSection().size());
auto alb = toAny(root.getAnyPointerField().getAs<List<TestAllTypes>>());
EXPECT_EQ(2, alb.size());
EXPECT_EQ(48, alb.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alb.as<List<AnyStruct>>()[0].getPointerSection().size());
auto alr = toAny(root.getAnyPointerField().getAs<List<TestAllTypes>>().asReader());
EXPECT_EQ(2, alr.size());
EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size());
alr = toAny(root.getAnyPointerField().getAs<List<TestAllTypes>>()).asReader();
EXPECT_EQ(2, alr.size());
EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size());
}
} // namespace } // namespace
} // namespace _ (private) } // namespace _ (private)
} // namespace capnp } // namespace capnp
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "layout.h" #include "layout.h"
#include "pointer-helpers.h" #include "pointer-helpers.h"
#include "orphan.h" #include "orphan.h"
#include "list.h"
namespace capnp { namespace capnp {
...@@ -35,6 +36,36 @@ class Orphanage; ...@@ -35,6 +36,36 @@ class Orphanage;
class ClientHook; class ClientHook;
class PipelineHook; class PipelineHook;
struct PipelineOp; struct PipelineOp;
struct AnyPointer;
struct AnyList {
AnyList() = delete;
class Reader;
class Builder;
};
struct AnyStruct {
AnyStruct() = delete;
class Reader;
class Builder;
class Pipeline;
};
template<>
struct List<AnyStruct, Kind::OTHER> {
List() = delete;
class Reader;
class Builder;
};
namespace _ { // private
template <> struct Kind_<AnyPointer> { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<AnyStruct> { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<AnyList> { static constexpr Kind kind = Kind::OTHER; };
} // namespace _ (private)
// ======================================================================================= // =======================================================================================
// AnyPointer! // AnyPointer!
...@@ -43,6 +74,8 @@ struct AnyPointer { ...@@ -43,6 +74,8 @@ struct AnyPointer {
// Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary
// object. // object.
AnyPointer() = delete;
class Reader { class Reader {
public: public:
typedef AnyPointer Reads; typedef AnyPointer Reads;
...@@ -54,6 +87,12 @@ struct AnyPointer { ...@@ -54,6 +87,12 @@ struct AnyPointer {
// Get the total size of the target object and all its children. // Get the total size of the target object and all its children.
inline bool isNull() const; inline bool isNull() const;
inline bool isStruct() {
return reader.isStruct();
}
inline bool isList() {
return reader.isList();
}
template <typename T> template <typename T>
inline ReaderFor<T> getAs() const; inline ReaderFor<T> getAs() const;
...@@ -96,6 +135,12 @@ struct AnyPointer { ...@@ -96,6 +135,12 @@ struct AnyPointer {
// Get the total size of the target object and all its children. // Get the total size of the target object and all its children.
inline bool isNull(); inline bool isNull();
inline bool isStruct() {
return builder.isStruct();
}
inline bool isList() {
return builder.isList();
}
inline void clear(); inline void clear();
// Set to null. // Set to null.
...@@ -132,6 +177,13 @@ struct AnyPointer { ...@@ -132,6 +177,13 @@ struct AnyPointer {
inline BuilderFor<T> initAs(ListSchema schema, uint elementCount); inline BuilderFor<T> initAs(ListSchema schema, uint elementCount);
// Only valid for T = DynamicList. Requires `#include <capnp/dynamic.h>`. // Only valid for T = DynamicList. Requires `#include <capnp/dynamic.h>`.
inline AnyList::Builder initAsAnyList(_::FieldSize elementSize, uint elementCount);
// Note: Does not accept INLINE_COMPOSITE for elementSize.
inline List<AnyStruct>::Builder initAsListOfAnyStruct(uint dataWordCount, uint pointerCount, uint elementCount);
inline AnyStruct::Builder initAsAnyStruct(uint dataWordCount, uint pointerCount);
template <typename T> template <typename T>
inline void setAs(ReaderFor<T> value); inline void setAs(ReaderFor<T> value);
// Valid for ReaderType = T::Reader for T = any generated struct type, List<U>, Text, Data, // Valid for ReaderType = T::Reader for T = any generated struct type, List<U>, Text, Data,
...@@ -195,11 +247,9 @@ struct AnyPointer { ...@@ -195,11 +247,9 @@ struct AnyPointer {
// Just make a copy. // Just make a copy.
Pipeline getPointerField(uint16_t pointerIndex); Pipeline getPointerField(uint16_t pointerIndex);
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index // Deprecated. In the future, we should use .asAnyStruct.getPointerField.
// of the sub-object within the pointer section of the result (the result must be a struct).
// inline AnyStruct::Pipeline asAnyStruct();
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
// Also make `ops` into a Vector to optimize this.
kj::Own<ClientHook> asCap(); kj::Own<ClientHook> asCap();
// Expect that the result is a capability and construct a pipelined version of it now. // Expect that the result is a capability and construct a pipelined version of it now.
...@@ -284,6 +334,282 @@ private: ...@@ -284,6 +334,282 @@ private:
friend class AnyPointer::Builder; friend class AnyPointer::Builder;
}; };
struct AnyList;
struct AnyStruct;
template <Kind k> struct AnyTypeFor_;
template <> struct AnyTypeFor_<Kind::STRUCT> { typedef AnyStruct Type; };
template <> struct AnyTypeFor_<Kind::LIST> { typedef AnyList Type; };
template <typename T>
using AnyTypeFor = typename AnyTypeFor_<kind<T>()>::Type;
template <typename T>
inline ReaderFor<AnyTypeFor<FromReader<T>>> toAny(T&& value) {
return ReaderFor<AnyTypeFor<FromReader<T> > >(
_::PointerHelpers<FromReader<T>>::getInternalReader(value));
}
template <typename T>
inline BuilderFor<AnyTypeFor<FromBuilder<T>>> toAny(T&& value) {
return BuilderFor<AnyTypeFor<FromBuilder<T> > >(
_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(value)));
}
template <>
struct List<AnyPointer, Kind::OTHER> {
List() = delete;
class Reader {
public:
typedef List<AnyPointer> Reads;
Reader() = default;
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename AnyPointer::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename AnyPointer::Reader> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class Builder {
public:
typedef List<AnyPointer> Builds;
Builder() = delete;
inline Builder(decltype(nullptr)) {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() { return Reader(builder.asReader()); }
inline Reader asReader() { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename AnyPointer::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS));
}
typedef _::IndexingIterator<Builder, typename AnyPointer::Builder> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
};
class AnyStruct::Reader {
public:
Reader() = default;
inline Reader(_::StructReader reader): _reader(reader) {}
Data::Reader getDataSection() {
return _reader.getDataSectionAsBlob();
}
List<AnyPointer>::Reader getPointerSection() {
return List<AnyPointer>::Reader(_reader.getPointerSectionAsList());
}
template <typename T>
ReaderFor<T> as();
// T must be a struct type.
private:
_::StructReader _reader;
};
class AnyStruct::Builder {
public:
inline Builder(decltype(nullptr)) {}
inline Builder(_::PointerBuilder builder, _::StructSize size, const word* defaultValue = nullptr): _builder(builder.getStruct(size, defaultValue)) {}
inline Builder(_::StructBuilder builder): _builder(builder) {}
inline Data::Builder getDataSection() {
return _builder.getDataSectionAsBlob();
}
List<AnyPointer>::Builder getPointerSection() {
return List<AnyPointer>::Builder(_builder.getPointerSectionAsList());
}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return Reader(_builder.asReader()); }
private:
_::StructBuilder _builder;
friend class Orphanage;
friend class CapBuilderContext;
};
class AnyStruct::Pipeline {
public:
Pipeline getPointerField(uint16_t pointerIndex);
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// of the sub-object within the pointer section of the result (the result must be a struct).
//
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
// Also make `ops` into a Vector to optimize this.
private:
kj::Own<PipelineHook> hook;
kj::Array<PipelineOp> ops;
inline Pipeline(kj::Own<PipelineHook>&& hook, kj::Array<PipelineOp>&& ops)
: hook(kj::mv(hook)), ops(kj::mv(ops)) {}
};
class List<AnyStruct, Kind::OTHER>::Reader {
public:
typedef List<AnyStruct> Reads;
Reader() = default;
inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; }
inline typename AnyStruct::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size());
return typename AnyStruct::Reader(reader.getStructElement(index * ELEMENTS));
}
typedef _::IndexingIterator<const Reader, typename AnyStruct::Reader> Iterator;
inline Iterator begin() const { return Iterator(this, 0); }
inline Iterator end() const { return Iterator(this, size()); }
private:
_::ListReader reader;
template <typename U, Kind K>
friend struct _::PointerHelpers;
template <typename U, Kind K>
friend struct List;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class List<AnyStruct, Kind::OTHER>::Builder {
public:
typedef List<AnyStruct> Builds;
Builder() = delete;
inline Builder(decltype(nullptr)) {}
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
inline operator Reader() { return Reader(builder.asReader()); }
inline Reader asReader() { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename AnyStruct::Builder operator[](uint index) {
KJ_IREQUIRE(index < size());
return typename AnyStruct::Builder(builder.getStructElement(index * ELEMENTS));
}
typedef _::IndexingIterator<Builder, typename AnyStruct::Builder> Iterator;
inline Iterator begin() { return Iterator(this, 0); }
inline Iterator end() { return Iterator(this, size()); }
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
};
class AnyList::Reader {
public:
Reader() = default;
inline Reader(_::ListReader reader): _reader(reader) {}
_::FieldSize getElementSize();
ElementCount size() {
return _reader.size();
}
template <typename T> ReaderFor<T> as() {
// T must be List<U>.
return ReaderFor<T>(_reader);
}
private:
_::ListReader _reader;
};
class AnyList::Builder {
public:
inline Builder(decltype(nullptr)) {}
inline Builder(_::PointerBuilder builder, _::FieldSize size, const word* defaultValue = nullptr): _builder(builder.getList(size, defaultValue)) {}
inline Builder(_::ListBuilder builder): _builder(builder) {}
_::FieldSize getElementSize();
ElementCount size() {
return _builder.size();
}
template <typename T> BuilderFor<T> as() {
// T must be List<U>.
return BuilderFor<T>(_builder);
}
inline operator Reader() const { return Reader(_builder.asReader()); }
inline Reader asReader() const { return Reader(_builder.asReader()); }
private:
_::ListBuilder _builder;
};
namespace _ { // (private)
template <>
struct PointerHelpers<AnyStruct, Kind::OTHER> {
static inline typename AnyStruct::Reader get(PointerReader reader, const word* defaultValue = nullptr) {
return typename AnyStruct::Reader(reader.getStruct(defaultValue));
}
static inline typename AnyStruct::Builder get(PointerBuilder builder,
const word* defaultValue = nullptr) {
return typename AnyStruct::Builder(builder, /* TODO: allow specifying the size! */ _::StructSize(0, 0), defaultValue);
}
static inline typename AnyStruct::Builder init(PointerBuilder builder, uint dataWordCount, uint pointerCount) {
return typename AnyStruct::Builder(builder.initStruct(StructSize(dataWordCount, pointerCount)));
}
};
template <>
struct PointerHelpers<AnyList, Kind::OTHER> {
static inline typename AnyList::Reader get(PointerReader reader, const word* defaultValue = nullptr) {
return typename AnyList::Reader(reader.getList(/* TODO: allow specifying the size! */ FieldSize::VOID, defaultValue));
}
static inline typename AnyList::Builder get(PointerBuilder builder,
const word* defaultValue = nullptr) {
return typename AnyList::Builder(builder, /* TODO: allow specifying the size! */ FieldSize::VOID, defaultValue);
}
static inline typename AnyList::Builder init(PointerBuilder builder, FieldSize elementSize, uint elementCount) {
return typename AnyList::Builder(builder.initList(elementSize, elementCount));
}
static inline typename AnyList::Builder init(PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) {
return typename AnyList::Builder(builder.initStructList(
elementCount,
StructSize(dataWordCount, pointerCount)));
}
};
} // end namespace _ (private)
// ======================================================================================= // =======================================================================================
// Pipeline helpers // Pipeline helpers
// //
...@@ -335,10 +661,6 @@ private: ...@@ -335,10 +661,6 @@ private:
// ======================================================================================= // =======================================================================================
// Inline implementation details // Inline implementation details
namespace _ { // private
template <> struct Kind_<AnyPointer> { static constexpr Kind kind = Kind::OTHER; };
} // namespace _ (private)
inline MessageSize AnyPointer::Reader::targetSize() const { inline MessageSize AnyPointer::Reader::targetSize() const {
return reader.targetSize().asPublic(); return reader.targetSize().asPublic();
} }
...@@ -379,6 +701,16 @@ inline BuilderFor<T> AnyPointer::Builder::initAs(uint elementCount) { ...@@ -379,6 +701,16 @@ inline BuilderFor<T> AnyPointer::Builder::initAs(uint elementCount) {
return _::PointerHelpers<T>::init(builder, elementCount); return _::PointerHelpers<T>::init(builder, elementCount);
} }
inline AnyList::Builder AnyPointer::Builder::initAsAnyList(_::FieldSize elementSize, uint elementCount) {
return _::PointerHelpers<AnyList>::init(builder, elementSize, elementCount);
}
// inline List<AnyStruct>::Builder AnyPointer::Builder::initAsListOfAnyStruct(uint dataWordCount, uint pointerCount, uint elementCount);
inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(uint dataWordCount, uint pointerCount) {
return _::PointerHelpers<AnyStruct>::init(builder, dataWordCount, pointerCount);
}
template <typename T> template <typename T>
inline void AnyPointer::Builder::setAs(ReaderFor<T> value) { inline void AnyPointer::Builder::setAs(ReaderFor<T> value) {
return _::PointerHelpers<T>::set(builder, value); return _::PointerHelpers<T>::set(builder, value);
...@@ -406,6 +738,8 @@ inline Orphan<AnyPointer> AnyPointer::Builder::disown() { ...@@ -406,6 +738,8 @@ inline Orphan<AnyPointer> AnyPointer::Builder::disown() {
template <> struct ReaderFor_ <AnyPointer, Kind::OTHER> { typedef AnyPointer::Reader Type; }; template <> struct ReaderFor_ <AnyPointer, Kind::OTHER> { typedef AnyPointer::Reader Type; };
template <> struct BuilderFor_<AnyPointer, Kind::OTHER> { typedef AnyPointer::Builder Type; }; template <> struct BuilderFor_<AnyPointer, Kind::OTHER> { typedef AnyPointer::Builder Type; };
template <> struct ReaderFor_ <AnyStruct, Kind::OTHER> { typedef AnyStruct::Reader Type; };
template <> struct BuilderFor_<AnyStruct, Kind::OTHER> { typedef AnyStruct::Builder Type; };
template <> template <>
struct Orphanage::GetInnerReader<AnyPointer, Kind::OTHER> { struct Orphanage::GetInnerReader<AnyPointer, Kind::OTHER> {
......
...@@ -1700,6 +1700,8 @@ private: ...@@ -1700,6 +1700,8 @@ private:
" template <typename, ::capnp::Kind>\n" " template <typename, ::capnp::Kind>\n"
" friend struct ::capnp::ToDynamic_;\n" " friend struct ::capnp::ToDynamic_;\n"
" friend class ::capnp::Orphanage;\n", " friend class ::capnp::Orphanage;\n",
" template <typename, ::capnp::Kind>\n"
" friend struct ::capnp::_::PointerHelpers;\n"
"};\n" "};\n"
"\n"); "\n");
} }
......
...@@ -251,6 +251,7 @@ struct WirePointer { ...@@ -251,6 +251,7 @@ struct WirePointer {
// our "null" value. // our "null" value.
return (offsetAndKind.get() == 0) & (upper32Bits == 0); return (offsetAndKind.get() == 0) & (upper32Bits == 0);
} }
}; };
static_assert(sizeof(WirePointer) == sizeof(word), static_assert(sizeof(WirePointer) == sizeof(word),
"capnp::WirePointer is not exactly one word. This will probably break everything."); "capnp::WirePointer is not exactly one word. This will probably break everything.");
...@@ -2155,6 +2156,20 @@ bool PointerBuilder::isNull() { ...@@ -2155,6 +2156,20 @@ bool PointerBuilder::isNull() {
return pointer->isNull(); return pointer->isNull();
} }
bool PointerBuilder::isStruct() {
word* refTarget;
WirePointer* ptr = pointer;
WireHelpers::followFars(ptr, refTarget, segment);
return ptr->kind() == WirePointer::Kind::STRUCT;
}
bool PointerBuilder::isList() {
word* refTarget;
WirePointer* ptr = pointer;
WireHelpers::followFars(ptr, refTarget, segment);
return ptr->kind() == WirePointer::Kind::LIST;
}
void PointerBuilder::transferFrom(PointerBuilder other) { void PointerBuilder::transferFrom(PointerBuilder other) {
if (!pointer->isNull()) { if (!pointer->isNull()) {
WireHelpers::zeroObject(segment, pointer); WireHelpers::zeroObject(segment, pointer);
...@@ -2238,6 +2253,22 @@ bool PointerReader::isNull() const { ...@@ -2238,6 +2253,22 @@ bool PointerReader::isNull() const {
return pointer == nullptr || pointer->isNull(); return pointer == nullptr || pointer->isNull();
} }
bool PointerReader::isStruct() const {
word* refTarget;
const WirePointer* ptr = pointer;
SegmentReader* sgmt = segment;
WireHelpers::followFars(ptr, refTarget, sgmt);
return ptr->kind() == WirePointer::Kind::STRUCT;
}
bool PointerReader::isList() const {
word* refTarget;
const WirePointer* ptr = pointer;
SegmentReader* sgmt = segment;
WireHelpers::followFars(ptr, refTarget, sgmt);
return ptr->kind() == WirePointer::Kind::LIST;
}
kj::Maybe<Arena&> PointerReader::getArena() const { kj::Maybe<Arena&> PointerReader::getArena() const {
return segment == nullptr ? nullptr : segment->getArena(); return segment == nullptr ? nullptr : segment->getArena();
} }
......
...@@ -324,6 +324,8 @@ public: ...@@ -324,6 +324,8 @@ public:
// location. // location.
bool isNull(); bool isNull();
bool isStruct();
bool isList();
StructBuilder getStruct(StructSize size, const word* defaultValue); StructBuilder getStruct(StructSize size, const word* defaultValue);
ListBuilder getList(FieldSize elementSize, const word* defaultValue); ListBuilder getList(FieldSize elementSize, const word* defaultValue);
...@@ -402,6 +404,8 @@ public: ...@@ -402,6 +404,8 @@ public:
// exception if it overruns. // exception if it overruns.
bool isNull() const; bool isNull() const;
bool isStruct() const;
bool isList() const;
StructReader getStruct(const word* defaultValue) const; StructReader getStruct(const word* defaultValue) const;
ListReader getList(FieldSize expectedElementSize, const word* defaultValue) const; ListReader getList(FieldSize expectedElementSize, const word* defaultValue) const;
...@@ -452,6 +456,7 @@ public: ...@@ -452,6 +456,7 @@ public:
inline BitCount getDataSectionSize() const { return dataSize; } inline BitCount getDataSectionSize() const { return dataSize; }
inline WirePointerCount getPointerSectionSize() const { return pointerCount; } inline WirePointerCount getPointerSectionSize() const { return pointerCount; }
inline Data::Builder getDataSectionAsBlob(); inline Data::Builder getDataSectionAsBlob();
inline _::ListBuilder getPointerSectionAsList();
template <typename T> template <typename T>
KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset)); KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset));
...@@ -532,6 +537,7 @@ public: ...@@ -532,6 +537,7 @@ public:
inline BitCount getDataSectionSize() const { return dataSize; } inline BitCount getDataSectionSize() const { return dataSize; }
inline WirePointerCount getPointerSectionSize() const { return pointerCount; } inline WirePointerCount getPointerSectionSize() const { return pointerCount; }
inline Data::Reader getDataSectionAsBlob(); inline Data::Reader getDataSectionAsBlob();
inline _::ListReader getPointerSectionAsList();
template <typename T> template <typename T>
KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const); KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const);
...@@ -662,6 +668,7 @@ private: ...@@ -662,6 +668,7 @@ private:
friend class StructBuilder; friend class StructBuilder;
friend struct WireHelpers; friend struct WireHelpers;
friend class OrphanBuilder; friend class OrphanBuilder;
friend class AnyStruct;
}; };
class ListReader { class ListReader {
...@@ -846,6 +853,10 @@ inline Data::Builder StructBuilder::getDataSectionAsBlob() { ...@@ -846,6 +853,10 @@ inline Data::Builder StructBuilder::getDataSectionAsBlob() {
return Data::Builder(reinterpret_cast<byte*>(data), dataSize / BITS_PER_BYTE / BYTES); return Data::Builder(reinterpret_cast<byte*>(data), dataSize / BITS_PER_BYTE / BYTES);
} }
inline _::ListBuilder StructBuilder::getPointerSectionAsList() {
return _::ListBuilder(segment, pointers, pointerCount * BITS_PER_WORD / ELEMENTS, pointerCount, 0, 1, FieldSize::POINTER);
}
template <typename T> template <typename T>
inline bool StructBuilder::hasDataField(ElementCount offset) { inline bool StructBuilder::hasDataField(ElementCount offset) {
return getDataField<Mask<T>>(offset) != 0; return getDataField<Mask<T>>(offset) != 0;
...@@ -924,6 +935,10 @@ inline Data::Reader StructReader::getDataSectionAsBlob() { ...@@ -924,6 +935,10 @@ inline Data::Reader StructReader::getDataSectionAsBlob() {
return Data::Reader(reinterpret_cast<const byte*>(data), dataSize / BITS_PER_BYTE / BYTES); return Data::Reader(reinterpret_cast<const byte*>(data), dataSize / BITS_PER_BYTE / BYTES);
} }
inline _::ListReader StructReader::getPointerSectionAsList() {
return _::ListReader(segment, pointers, pointerCount, pointerCount * BITS_PER_WORD / ELEMENTS, 0, 1, FieldSize::POINTER, nestingLimit);
}
template <typename T> template <typename T>
inline bool StructReader::hasDataField(ElementCount offset) const { inline bool StructReader::hasDataField(ElementCount offset) const {
return getDataField<Mask<T>>(offset) != 0; return getDataField<Mask<T>>(offset) != 0;
......
...@@ -163,6 +163,8 @@ struct List<T, Kind::PRIMITIVE> { ...@@ -163,6 +163,8 @@ struct List<T, Kind::PRIMITIVE> {
private: private:
_::ListBuilder builder; _::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage; friend class Orphanage;
template <typename U, Kind K> template <typename U, Kind K>
friend struct ToDynamic_; friend struct ToDynamic_;
...@@ -282,6 +284,8 @@ struct List<T, Kind::STRUCT> { ...@@ -282,6 +284,8 @@ struct List<T, Kind::STRUCT> {
private: private:
_::ListBuilder builder; _::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage; friend class Orphanage;
template <typename U, Kind K> template <typename U, Kind K>
friend struct ToDynamic_; friend struct ToDynamic_;
...@@ -391,6 +395,8 @@ struct List<List<T>, Kind::LIST> { ...@@ -391,6 +395,8 @@ struct List<List<T>, Kind::LIST> {
private: private:
_::ListBuilder builder; _::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage; friend class Orphanage;
template <typename U, Kind K> template <typename U, Kind K>
friend struct ToDynamic_; friend struct ToDynamic_;
...@@ -487,6 +493,8 @@ struct List<T, Kind::BLOB> { ...@@ -487,6 +493,8 @@ struct List<T, Kind::BLOB> {
private: private:
_::ListBuilder builder; _::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage; friend class Orphanage;
template <typename U, Kind K> template <typename U, Kind K>
friend struct ToDynamic_; friend struct ToDynamic_;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "layout.h" #include "layout.h"
#include "list.h" #include "list.h"
// #include "any.h"
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
...@@ -53,13 +54,12 @@ struct PointerHelpers<T, Kind::STRUCT> { ...@@ -53,13 +54,12 @@ struct PointerHelpers<T, Kind::STRUCT> {
static inline Orphan<T> disown(PointerBuilder builder) { static inline Orphan<T> disown(PointerBuilder builder) {
return Orphan<T>(builder.disown()); return Orphan<T>(builder.disown());
} }
static inline _::StructReader getInternalReader(const typename T::Reader& reader) { static inline _::StructReader getInternalReader(const typename T::Reader& reader) {
// TODO(cleanup): This is used by RpcSystem::Connect, but perhaps it should be used more
// broadly so that we can reduce the number of friends declared by every Reader type.
return reader._reader; return reader._reader;
} }
static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) {
return builder._builder;
}
}; };
template <typename T> template <typename T>
...@@ -91,6 +91,12 @@ struct PointerHelpers<List<T>, Kind::LIST> { ...@@ -91,6 +91,12 @@ struct PointerHelpers<List<T>, Kind::LIST> {
static inline Orphan<List<T>> disown(PointerBuilder builder) { static inline Orphan<List<T>> disown(PointerBuilder builder) {
return Orphan<List<T>>(builder.disown()); return Orphan<List<T>>(builder.disown());
} }
static inline _::ListReader getInternalReader(const typename List<T>::Reader& reader) {
return reader.reader;
}
static inline _::ListBuilder getInternalBuilder(typename List<T>::Builder&& builder) {
return builder.builder;
}
}; };
template <typename T> template <typename T>
......
...@@ -115,8 +115,8 @@ Lists of structs use the smallest element size in which the struct can fit. So, ...@@ -115,8 +115,8 @@ Lists of structs use the smallest element size in which the struct can fit. So,
list of structs that each contain two `UInt8` fields and nothing else could be encoded with C = 3 list of structs that each contain two `UInt8` fields and nothing else could be encoded with C = 3
(2-byte elements). A list of structs that each contain a single `Text` field would be encoded as (2-byte elements). A list of structs that each contain a single `Text` field would be encoded as
C = 6 (pointer elements). A list of structs that each contain a single `Bool` field would be C = 6 (pointer elements). A list of structs that each contain a single `Bool` field would be
encoded using C = 1 (1-bit elements). A list structs which are each more than one word in size encoded using C = 1 (1-bit elements). A list of structs which are each more than one word in size
must be be encoded using C = 7 (composite). must be encoded using C = 7 (composite).
When C = 7, the elements of the list are fixed-width composite values -- usually, structs. In When C = 7, the elements of the list are fixed-width composite values -- usually, structs. In
this case, the list content is prefixed by a "tag" word that describes each individual element. this case, the list content is prefixed by a "tag" word that describes each individual element.
......
...@@ -67,7 +67,7 @@ Glad you asked! ...@@ -67,7 +67,7 @@ Glad you asked!
order of magnitude or more. In fact, usually it's no more than some inline accessor methods! order of magnitude or more. In fact, usually it's no more than some inline accessor methods!
* **Tiny runtime library:** Due to the simplicity of the Cap'n Proto format, the runtime library * **Tiny runtime library:** Due to the simplicity of the Cap'n Proto format, the runtime library
can be much smaller. can be much smaller.
* **Time-traveling RPC:** Cap'n Proto features an RPC system implements [time travel](rpc.html) * **Time-traveling RPC:** Cap'n Proto features an RPC system that implements [time travel](rpc.html)
such that call results are returned to the client before the request even arrives at the server! such that call results are returned to the client before the request even arrives at the server!
<a href="rpc.html"><img src='images/time-travel.png' style='max-width:639px'></a> <a href="rpc.html"><img src='images/time-travel.png' style='max-width:639px'></a>
......
...@@ -118,6 +118,7 @@ interface Filesystem { ...@@ -118,6 +118,7 @@ interface Filesystem {
{% endhighlight %} {% endhighlight %}
We've now solved our latency problem... but at what cost? We've now solved our latency problem... but at what cost?
* We now have to implement path string manipulation, which is always a headache. * We now have to implement path string manipulation, which is always a headache.
* If someone wants to perform multiple operations on a file or directory, we now either have to * If someone wants to perform multiple operations on a file or directory, we now either have to
re-allocate resources for every call or we have to implement some sort of cache, which tends to re-allocate resources for every call or we have to implement some sort of cache, which tends to
......
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