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) {
}
}
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 _ (private)
} // namespace capnp
This diff is collapsed.
......@@ -1700,6 +1700,8 @@ private:
" template <typename, ::capnp::Kind>\n"
" friend struct ::capnp::ToDynamic_;\n"
" friend class ::capnp::Orphanage;\n",
" template <typename, ::capnp::Kind>\n"
" friend struct ::capnp::_::PointerHelpers;\n"
"};\n"
"\n");
}
......
......@@ -251,6 +251,7 @@ struct WirePointer {
// our "null" value.
return (offsetAndKind.get() == 0) & (upper32Bits == 0);
}
};
static_assert(sizeof(WirePointer) == sizeof(word),
"capnp::WirePointer is not exactly one word. This will probably break everything.");
......@@ -2155,6 +2156,20 @@ bool PointerBuilder::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) {
if (!pointer->isNull()) {
WireHelpers::zeroObject(segment, pointer);
......@@ -2238,6 +2253,22 @@ bool PointerReader::isNull() const {
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 {
return segment == nullptr ? nullptr : segment->getArena();
}
......
......@@ -324,6 +324,8 @@ public:
// location.
bool isNull();
bool isStruct();
bool isList();
StructBuilder getStruct(StructSize size, const word* defaultValue);
ListBuilder getList(FieldSize elementSize, const word* defaultValue);
......@@ -402,6 +404,8 @@ public:
// exception if it overruns.
bool isNull() const;
bool isStruct() const;
bool isList() const;
StructReader getStruct(const word* defaultValue) const;
ListReader getList(FieldSize expectedElementSize, const word* defaultValue) const;
......@@ -452,6 +456,7 @@ public:
inline BitCount getDataSectionSize() const { return dataSize; }
inline WirePointerCount getPointerSectionSize() const { return pointerCount; }
inline Data::Builder getDataSectionAsBlob();
inline _::ListBuilder getPointerSectionAsList();
template <typename T>
KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset));
......@@ -532,6 +537,7 @@ public:
inline BitCount getDataSectionSize() const { return dataSize; }
inline WirePointerCount getPointerSectionSize() const { return pointerCount; }
inline Data::Reader getDataSectionAsBlob();
inline _::ListReader getPointerSectionAsList();
template <typename T>
KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const);
......@@ -662,6 +668,7 @@ private:
friend class StructBuilder;
friend struct WireHelpers;
friend class OrphanBuilder;
friend class AnyStruct;
};
class ListReader {
......@@ -846,6 +853,10 @@ inline Data::Builder StructBuilder::getDataSectionAsBlob() {
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>
inline bool StructBuilder::hasDataField(ElementCount offset) {
return getDataField<Mask<T>>(offset) != 0;
......@@ -924,6 +935,10 @@ inline Data::Reader StructReader::getDataSectionAsBlob() {
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>
inline bool StructReader::hasDataField(ElementCount offset) const {
return getDataField<Mask<T>>(offset) != 0;
......
......@@ -163,6 +163,8 @@ struct List<T, Kind::PRIMITIVE> {
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
......@@ -282,6 +284,8 @@ struct List<T, Kind::STRUCT> {
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
......@@ -391,6 +395,8 @@ struct List<List<T>, Kind::LIST> {
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
......@@ -487,6 +493,8 @@ struct List<T, Kind::BLOB> {
private:
_::ListBuilder builder;
template <typename U, Kind K>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U, Kind K>
friend struct ToDynamic_;
......
......@@ -24,6 +24,7 @@
#include "layout.h"
#include "list.h"
// #include "any.h"
namespace capnp {
namespace _ { // private
......@@ -53,13 +54,12 @@ struct PointerHelpers<T, Kind::STRUCT> {
static inline Orphan<T> disown(PointerBuilder builder) {
return Orphan<T>(builder.disown());
}
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;
}
static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) {
return builder._builder;
}
};
template <typename T>
......@@ -91,6 +91,12 @@ struct PointerHelpers<List<T>, Kind::LIST> {
static inline Orphan<List<T>> disown(PointerBuilder builder) {
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>
......
......@@ -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
(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
encoded using C = 1 (1-bit elements). A list structs which are each more than one word in size
must be be encoded using C = 7 (composite).
encoded using C = 1 (1-bit elements). A list of structs which are each more than one word in size
must be encoded using C = 7 (composite).
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.
......
......@@ -67,7 +67,7 @@ Glad you asked!
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
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!
<a href="rpc.html"><img src='images/time-travel.png' style='max-width:639px'></a>
......
......@@ -118,6 +118,7 @@ interface Filesystem {
{% endhighlight %}
We've now solved our latency problem... but at what cost?
* 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
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