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
This diff is collapsed.
...@@ -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