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
......@@ -25,6 +25,7 @@
#include "layout.h"
#include "pointer-helpers.h"
#include "orphan.h"
#include "list.h"
namespace capnp {
......@@ -35,6 +36,36 @@ class Orphanage;
class ClientHook;
class PipelineHook;
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!
......@@ -43,6 +74,8 @@ struct AnyPointer {
// Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary
// object.
AnyPointer() = delete;
class Reader {
public:
typedef AnyPointer Reads;
......@@ -54,6 +87,12 @@ struct AnyPointer {
// Get the total size of the target object and all its children.
inline bool isNull() const;
inline bool isStruct() {
return reader.isStruct();
}
inline bool isList() {
return reader.isList();
}
template <typename T>
inline ReaderFor<T> getAs() const;
......@@ -96,6 +135,12 @@ struct AnyPointer {
// Get the total size of the target object and all its children.
inline bool isNull();
inline bool isStruct() {
return builder.isStruct();
}
inline bool isList() {
return builder.isList();
}
inline void clear();
// Set to null.
......@@ -132,6 +177,13 @@ struct AnyPointer {
inline BuilderFor<T> initAs(ListSchema schema, uint elementCount);
// 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>
inline void setAs(ReaderFor<T> value);
// Valid for ReaderType = T::Reader for T = any generated struct type, List<U>, Text, Data,
......@@ -195,11 +247,9 @@ struct AnyPointer {
// Just make a copy.
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.
// Deprecated. In the future, we should use .asAnyStruct.getPointerField.
inline AnyStruct::Pipeline asAnyStruct();
kj::Own<ClientHook> asCap();
// Expect that the result is a capability and construct a pipelined version of it now.
......@@ -284,6 +334,282 @@ private:
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
//
......@@ -335,10 +661,6 @@ private:
// =======================================================================================
// Inline implementation details
namespace _ { // private
template <> struct Kind_<AnyPointer> { static constexpr Kind kind = Kind::OTHER; };
} // namespace _ (private)
inline MessageSize AnyPointer::Reader::targetSize() const {
return reader.targetSize().asPublic();
}
......@@ -379,6 +701,16 @@ inline BuilderFor<T> AnyPointer::Builder::initAs(uint 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>
inline void AnyPointer::Builder::setAs(ReaderFor<T> value) {
return _::PointerHelpers<T>::set(builder, value);
......@@ -406,6 +738,8 @@ inline Orphan<AnyPointer> AnyPointer::Builder::disown() {
template <> struct ReaderFor_ <AnyPointer, Kind::OTHER> { typedef AnyPointer::Reader 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 <>
struct Orphanage::GetInnerReader<AnyPointer, Kind::OTHER> {
......
......@@ -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