Commit 35adf54b authored by Kenton Varda's avatar Kenton Varda

Implement ability to set() struct and list fields by deep-copying from a…

Implement ability to set() struct and list fields by deep-copying from a corresponding Reader.  This copy requires no schema knowledge.
parent d43aec91
...@@ -509,12 +509,6 @@ Data::Builder DynamicStruct::Builder::initObjectAsData(Text::Reader name, uint s ...@@ -509,12 +509,6 @@ Data::Builder DynamicStruct::Builder::initObjectAsData(Text::Reader name, uint s
return initObjectAsText(schema.getMemberByName(name), size); return initObjectAsText(schema.getMemberByName(name), size);
} }
void DynamicStruct::Builder::copyFrom(Reader other) {
// TODO(now): copyFrom on StructBuilder.
// TODO(now): don't forget to check types match.
FAIL_CHECK("Unimplemented: copyFrom()");
}
DynamicValue::Reader DynamicStruct::Reader::getImpl( DynamicValue::Reader DynamicStruct::Reader::getImpl(
internal::StructReader reader, StructSchema::Member member) { internal::StructReader reader, StructSchema::Member member) {
switch (member.getProto().getBody().which()) { switch (member.getProto().getBody().which()) {
...@@ -821,25 +815,17 @@ void DynamicStruct::Builder::setImpl( ...@@ -821,25 +815,17 @@ void DynamicStruct::Builder::setImpl(
return; return;
case schema::Type::Body::LIST_TYPE: { case schema::Type::Body::LIST_TYPE: {
// TODO(now): We need to do a schemaless copy to avoid losing information if the values builder.setListField(field.getOffset() * POINTERS, value.as<DynamicList>().reader);
// are larger than what the schema defines.
auto listValue = value.as<DynamicList>();
initImpl(builder, member, listValue.size())
.as<DynamicList>().copyFrom(listValue);
return; return;
} }
case schema::Type::Body::STRUCT_TYPE: { case schema::Type::Body::STRUCT_TYPE: {
// TODO(now): We need to do a schemaless copy to avoid losing information if the values builder.setStructField(field.getOffset() * POINTERS, value.as<DynamicStruct>().reader);
// are larger than what the schema defines.
initImpl(builder, member).as<DynamicStruct>()
.copyFrom(value.as<DynamicStruct>());
return; return;
} }
case schema::Type::Body::OBJECT_TYPE: { case schema::Type::Body::OBJECT_TYPE: {
// TODO(now): Perform schemaless copy. builder.setObjectField(field.getOffset() * POINTERS, value.as<DynamicObject>().reader);
FAIL_CHECK("TODO");
return; return;
} }
...@@ -1094,17 +1080,15 @@ void DynamicList::Builder::set(uint index, DynamicValue::Reader value) { ...@@ -1094,17 +1080,15 @@ void DynamicList::Builder::set(uint index, DynamicValue::Reader value) {
break; break;
case schema::Type::Body::LIST_TYPE: { case schema::Type::Body::LIST_TYPE: {
// TODO(now): Perform schemaless copy. builder.setListElement(index * ELEMENTS, value.as<DynamicList>().reader);
auto listValue = value.as<DynamicList>();
init(index, listValue.size()).as<DynamicList>().copyFrom(listValue);
break; break;
} }
case schema::Type::Body::STRUCT_TYPE: case schema::Type::Body::STRUCT_TYPE:
// Note we can't do a schemaless copy here because the space is already allocated. // Not supported for the same reason List<struct> doesn't support it -- the space for the
DynamicStruct::Builder( // element is already allocated, and if it's smaller than the input value the copy would
schema.getStructElementType(), builder.getStructElement(index * ELEMENTS)) // have to be lossy.
.copyFrom(value.as<DynamicStruct>()); FAIL_RECOVERABLE_CHECK("DynamicList of structs does not support set().");
break; break;
case schema::Type::Body::ENUM_TYPE: { case schema::Type::Body::ENUM_TYPE: {
...@@ -1188,12 +1172,6 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) { ...@@ -1188,12 +1172,6 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
return DynamicValue::Builder(); return DynamicValue::Builder();
} }
void DynamicList::Builder::copyFrom(Reader other) {
// TODO(now): copyFrom on ListBuilder.
// TODO(now): don't forget to check types match.
FAIL_CHECK("Unimplemented: copyFrom()");
}
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) { void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
PRECOND(value.size() == size(), "DynamicList::copyFrom() argument had different size."); PRECOND(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
uint i = 0; uint i = 0;
...@@ -1401,8 +1379,7 @@ DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::getDynamic( ...@@ -1401,8 +1379,7 @@ DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::getDynamic(
} }
void PointerHelpers<DynamicStruct, Kind::UNKNOWN>::set( void PointerHelpers<DynamicStruct, Kind::UNKNOWN>::set(
StructBuilder builder, WirePointerCount index, DynamicStruct::Reader value) { StructBuilder builder, WirePointerCount index, DynamicStruct::Reader value) {
// TODO(now): schemaless copy builder.setStructField(index, value.reader);
FAIL_CHECK("Unimplemented: copyFrom()");
} }
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::init( DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::init(
StructBuilder builder, WirePointerCount index, StructSchema schema) { StructBuilder builder, WirePointerCount index, StructSchema schema) {
...@@ -1429,8 +1406,7 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic( ...@@ -1429,8 +1406,7 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic(
} }
void PointerHelpers<DynamicList, Kind::UNKNOWN>::set( void PointerHelpers<DynamicList, Kind::UNKNOWN>::set(
StructBuilder builder, WirePointerCount index, DynamicList::Reader value) { StructBuilder builder, WirePointerCount index, DynamicList::Reader value) {
// TODO(now): schemaless copy builder.setListField(index, value.reader);
FAIL_CHECK("Unimplemented: copyFrom()");
} }
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init( DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
StructBuilder builder, WirePointerCount index, ListSchema schema, uint size) { StructBuilder builder, WirePointerCount index, ListSchema schema, uint size) {
......
...@@ -333,8 +333,6 @@ public: ...@@ -333,8 +333,6 @@ public:
Data::Builder initObjectAsData(Text::Reader name, uint size); Data::Builder initObjectAsData(Text::Reader name, uint size);
// Shortcuts to access members by name. These throw exceptions if no such field exists. // Shortcuts to access members by name. These throw exceptions if no such field exists.
void copyFrom(Reader other);
Reader asReader(); Reader asReader();
private: private:
...@@ -446,7 +444,6 @@ public: ...@@ -446,7 +444,6 @@ public:
inline iterator begin() { return iterator(this, 0); } inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, size()); } inline iterator end() { return iterator(this, size()); }
void copyFrom(Reader other);
void copyFrom(std::initializer_list<DynamicValue::Reader> value); void copyFrom(std::initializer_list<DynamicValue::Reader> value);
Reader asReader(); Reader asReader();
......
This diff is collapsed.
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
namespace capnproto { namespace capnproto {
class MessageBuilder; // So that it can be declared a friend.
template <typename T, Kind k = kind<T>()> template <typename T, Kind k = kind<T>()>
struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend.
...@@ -50,8 +52,7 @@ struct PointerHelpers<T, Kind::STRUCT> { ...@@ -50,8 +52,7 @@ struct PointerHelpers<T, Kind::STRUCT> {
} }
static inline void set(StructBuilder builder, WirePointerCount index, static inline void set(StructBuilder builder, WirePointerCount index,
typename T::Reader value) { typename T::Reader value) {
// TODO(now): schemaless copy builder.setStructField(index, value._reader);
CAPNPROTO_INLINE_PRECOND(false, "Not implemented: set() for struct fields.");
} }
static inline typename T::Builder init(StructBuilder builder, WirePointerCount index) { static inline typename T::Builder init(StructBuilder builder, WirePointerCount index) {
return typename T::Builder(builder.initStructField(index, structSize<T>())); return typename T::Builder(builder.initStructField(index, structSize<T>()));
...@@ -70,11 +71,15 @@ struct PointerHelpers<List<T>, Kind::LIST> { ...@@ -70,11 +71,15 @@ struct PointerHelpers<List<T>, Kind::LIST> {
} }
static inline void set(StructBuilder builder, WirePointerCount index, static inline void set(StructBuilder builder, WirePointerCount index,
typename List<T>::Reader value) { typename List<T>::Reader value) {
init(builder, index, value.size()).copyFrom(value); builder.setListField(index, value.reader);
}
template <typename U>
static void set(StructBuilder builder, WirePointerCount index, std::initializer_list<U> value) {
auto l = init(builder, index, value.size());
uint i = 0;
for (auto& element: value) {
l.set(i++, element);
} }
static inline void set(StructBuilder builder, WirePointerCount index,
std::initializer_list<ReaderFor<T>> value) {
init(builder, index, value.size()).copyFrom(value);
} }
static inline typename List<T>::Builder init( static inline typename List<T>::Builder init(
StructBuilder builder, WirePointerCount index, uint size) { StructBuilder builder, WirePointerCount index, uint size) {
......
...@@ -1070,6 +1070,104 @@ struct WireHelpers { ...@@ -1070,6 +1070,104 @@ struct WireHelpers {
} }
} }
static void setStructPointer(SegmentBuilder* segment, WirePointer* ref, StructReader value) {
WordCount dataSize = roundUpToWords(value.dataSize);
WordCount totalSize = dataSize + value.pointerCount * WORDS_PER_POINTER;
word* ptr = allocate(ref, segment, totalSize, WirePointer::STRUCT);
ref->structRef.set(dataSize, value.pointerCount);
if (value.dataSize == 1 * BITS) {
*reinterpret_cast<char*>(ptr) = value.getDataField<bool>(0 * ELEMENTS);
} else {
memcpy(ptr, value.data, value.dataSize / BITS_PER_BYTE / BYTES);
}
WirePointer* pointerSection = reinterpret_cast<WirePointer*>(ptr + dataSize);
for (uint i = 0; i < value.pointerCount / POINTERS; i++) {
setObjectPointer(segment, pointerSection + i, readObjectPointer(
value.segment, value.pointers + i, nullptr, value.nestingLimit));
}
}
static void setListPointer(SegmentBuilder* segment, WirePointer* ref, ListReader value) {
WordCount totalSize = roundUpToWords(value.elementCount * value.step);
if (value.step * ELEMENTS <= BITS_PER_WORD * WORDS) {
// List of non-structs.
word* ptr = allocate(ref, segment, totalSize, WirePointer::LIST);
if (value.structPointerCount == 1 * POINTERS) {
// List of pointers.
ref->listRef.set(FieldSize::POINTER, value.elementCount);
for (uint i = 0; i < value.elementCount / ELEMENTS; i++) {
setObjectPointer(segment, reinterpret_cast<WirePointer*>(ptr) + i, readObjectPointer(
value.segment, reinterpret_cast<const WirePointer*>(value.ptr) + i,
nullptr, value.nestingLimit));
}
} else {
// List of data.
FieldSize elementSize = FieldSize::VOID;
switch (value.step * ELEMENTS / BITS) {
case 0: elementSize = FieldSize::VOID; break;
case 1: elementSize = FieldSize::BIT; break;
case 8: elementSize = FieldSize::BYTE; break;
case 16: elementSize = FieldSize::TWO_BYTES; break;
case 32: elementSize = FieldSize::FOUR_BYTES; break;
case 64: elementSize = FieldSize::EIGHT_BYTES; break;
default:
FAIL_CHECK("invalid list step size", value.step * ELEMENTS / BITS);
break;
}
ref->listRef.set(elementSize, value.elementCount);
memcpy(ptr, value.ptr, totalSize * BYTES_PER_WORD / BYTES);
}
} else {
// List of structs.
word* ptr = allocate(ref, segment, totalSize + POINTER_SIZE_IN_WORDS, WirePointer::LIST);
ref->listRef.setInlineComposite(totalSize);
WordCount dataSize = roundUpToWords(value.structDataSize);
WirePointerCount pointerCount = value.structPointerCount;
WirePointer* tag = reinterpret_cast<WirePointer*>(ptr);
tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, value.elementCount);
tag->structRef.set(dataSize, pointerCount);
ptr += POINTER_SIZE_IN_WORDS;
const word* src = reinterpret_cast<const word*>(value.ptr);
for (uint i = 0; i < value.elementCount / ELEMENTS; i++) {
memcpy(ptr, src, value.structDataSize / BITS_PER_BYTE / BYTES);
ptr += dataSize;
src += dataSize;
for (uint j = 0; j < pointerCount / POINTERS; j++) {
setObjectPointer(segment, reinterpret_cast<WirePointer*>(ptr), readObjectPointer(
value.segment, reinterpret_cast<const WirePointer*>(src), nullptr,
value.nestingLimit));
ptr += POINTER_SIZE_IN_WORDS;
src += POINTER_SIZE_IN_WORDS;
}
}
}
}
static CAPNPROTO_ALWAYS_INLINE(void setObjectPointer(
SegmentBuilder* segment, WirePointer* ref, ObjectReader value)) {
switch (value.kind) {
case ObjectKind::NULL_POINTER:
memset(ref, 0, sizeof(*ref));
break;
case ObjectKind::STRUCT:
setStructPointer(segment, ref, value.structReader);
break;
case ObjectKind::LIST:
setListPointer(segment, ref, value.listReader);
break;
}
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
static CAPNPROTO_ALWAYS_INLINE(StructReader readStructPointer( static CAPNPROTO_ALWAYS_INLINE(StructReader readStructPointer(
...@@ -1377,12 +1475,15 @@ struct WireHelpers { ...@@ -1377,12 +1475,15 @@ struct WireHelpers {
} }
} }
static CAPNPROTO_ALWAYS_INLINE(ObjectReader readObjectPointer( static ObjectReader readObjectPointer(
SegmentReader* segment, const WirePointer* ref, SegmentReader* segment, const WirePointer* ref,
const word* defaultValue, int nestingLimit)) { const word* defaultValue, int nestingLimit) {
// We can't really reuse readStructPointer() and readListPointer() because they are designed // We can't really reuse readStructPointer() and readListPointer() because they are designed
// for the case where we are expecting a specific type, and they do validation around that, // for the case where we are expecting a specific type, and they do validation around that,
// whereas this method is for the case where we accept any pointer. // whereas this method is for the case where we accept any pointer.
//
// Not always-inline because it is called from several places in the copying code, and anyway
// is relatively rarely used.
const word* ptr; const word* ptr;
if (ref == nullptr || ref->isNull()) { if (ref == nullptr || ref->isNull()) {
...@@ -1498,6 +1599,10 @@ StructBuilder StructBuilder::initRoot( ...@@ -1498,6 +1599,10 @@ StructBuilder StructBuilder::initRoot(
reinterpret_cast<WirePointer*>(location), segment, size); reinterpret_cast<WirePointer*>(location), segment, size);
} }
void StructBuilder::setRoot(SegmentBuilder* segment, word* location, StructReader value) {
return WireHelpers::setStructPointer(segment, reinterpret_cast<WirePointer*>(location), value);
}
StructBuilder StructBuilder::getRoot( StructBuilder StructBuilder::getRoot(
SegmentBuilder* segment, word* location, StructSize size) { SegmentBuilder* segment, word* location, StructSize size) {
return WireHelpers::getWritableStructPointer( return WireHelpers::getWritableStructPointer(
...@@ -1575,6 +1680,18 @@ ObjectBuilder StructBuilder::getObjectField( ...@@ -1575,6 +1680,18 @@ ObjectBuilder StructBuilder::getObjectField(
return WireHelpers::getWritableObjectPointer(segment, pointers + ptrIndex, defaultValue); return WireHelpers::getWritableObjectPointer(segment, pointers + ptrIndex, defaultValue);
} }
void StructBuilder::setStructField(WirePointerCount ptrIndex, StructReader value) const {
return WireHelpers::setStructPointer(segment, pointers + ptrIndex, value);
}
void StructBuilder::setListField(WirePointerCount ptrIndex, ListReader value) const {
return WireHelpers::setListPointer(segment, pointers + ptrIndex, value);
}
void StructBuilder::setObjectField(WirePointerCount ptrIndex, ObjectReader value) const {
return WireHelpers::setObjectPointer(segment, pointers + ptrIndex, value);
}
StructReader StructBuilder::asReader() const { StructReader StructBuilder::asReader() const {
return StructReader(segment, data, pointers, return StructReader(segment, data, pointers,
dataSize, pointerCount, bit0Offset, std::numeric_limits<int>::max()); dataSize, pointerCount, bit0Offset, std::numeric_limits<int>::max());
...@@ -1743,6 +1860,16 @@ ObjectBuilder ListBuilder::getObjectElement(ElementCount index) const { ...@@ -1743,6 +1860,16 @@ ObjectBuilder ListBuilder::getObjectElement(ElementCount index) const {
segment, reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE), nullptr); segment, reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE), nullptr);
} }
void ListBuilder::setListElement(ElementCount index, ListReader value) const {
return WireHelpers::setListPointer(
segment, reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE), value);
}
void ListBuilder::setObjectElement(ElementCount index, ObjectReader value) const {
return WireHelpers::setObjectPointer(
segment, reinterpret_cast<WirePointer*>(ptr + index * step / BITS_PER_BYTE), value);
}
ListReader ListBuilder::asReader() const { ListReader ListBuilder::asReader() const {
return ListReader(segment, ptr, elementCount, step, structDataSize, structPointerCount, return ListReader(segment, ptr, elementCount, step, structDataSize, structPointerCount,
std::numeric_limits<int>::max()); std::numeric_limits<int>::max());
......
...@@ -296,6 +296,7 @@ public: ...@@ -296,6 +296,7 @@ public:
inline StructBuilder(): segment(nullptr), data(nullptr), pointers(nullptr), bit0Offset(0) {} inline StructBuilder(): segment(nullptr), data(nullptr), pointers(nullptr), bit0Offset(0) {}
static StructBuilder initRoot(SegmentBuilder* segment, word* location, StructSize size); static StructBuilder initRoot(SegmentBuilder* segment, word* location, StructSize size);
static void setRoot(SegmentBuilder* segment, word* location, StructReader value);
static StructBuilder getRoot(SegmentBuilder* segment, word* location, StructSize size); static StructBuilder getRoot(SegmentBuilder* segment, word* location, StructSize size);
inline BitCount getDataSectionSize() const { return dataSize; } inline BitCount getDataSectionSize() const { return dataSize; }
...@@ -376,6 +377,11 @@ public: ...@@ -376,6 +377,11 @@ public:
ObjectBuilder getObjectField(WirePointerCount ptrIndex, const word* defaultValue) const; ObjectBuilder getObjectField(WirePointerCount ptrIndex, const word* defaultValue) const;
// Read a pointer of arbitrary type. // Read a pointer of arbitrary type.
void setStructField(WirePointerCount ptrIndex, StructReader value) const;
void setListField(WirePointerCount ptrIndex, ListReader value) const;
void setObjectField(WirePointerCount ptrIndex, ObjectReader value) const;
// Sets a pointer field to a deep copy of the given value.
StructReader asReader() const; StructReader asReader() const;
// Gets a StructReader pointing at the same memory. // Gets a StructReader pointing at the same memory.
...@@ -555,6 +561,10 @@ public: ...@@ -555,6 +561,10 @@ public:
ObjectBuilder getObjectElement(ElementCount index) const; ObjectBuilder getObjectElement(ElementCount index) const;
// Gets a pointer element of arbitrary type. // Gets a pointer element of arbitrary type.
void setListElement(ElementCount index, ListReader value) const;
void setObjectElement(ElementCount index, ObjectReader value) const;
// Sets a pointer element to a deep copy of the given value.
ListReader asReader() const; ListReader asReader() const;
// Get a ListReader pointing at the same memory. // Get a ListReader pointing at the same memory.
......
...@@ -199,6 +199,10 @@ struct List<T, Kind::PRIMITIVE> { ...@@ -199,6 +199,10 @@ struct List<T, Kind::PRIMITIVE> {
private: private:
internal::ListReader reader; internal::ListReader reader;
template <typename U, Kind K>
friend struct internal::PointerHelpers;
template <typename U, Kind K>
friend struct List;
}; };
class Builder { class Builder {
...@@ -208,6 +212,9 @@ struct List<T, Kind::PRIMITIVE> { ...@@ -208,6 +212,9 @@ struct List<T, Kind::PRIMITIVE> {
Builder() = default; Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {} inline explicit Builder(internal::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 uint size() const { return builder.size() / ELEMENTS; }
inline T operator[](uint index) const { inline T operator[](uint index) const {
return builder.template getDataElement<T>(index * ELEMENTS); return builder.template getDataElement<T>(index * ELEMENTS);
...@@ -226,25 +233,6 @@ struct List<T, Kind::PRIMITIVE> { ...@@ -226,25 +233,6 @@ struct List<T, Kind::PRIMITIVE> {
inline iterator begin() const { return iterator(this, 0); } inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); } inline iterator end() const { return iterator(this, size()); }
template <typename Other>
void copyFrom(const Other& other) {
auto i = other.begin();
auto end = other.end();
uint pos = 0;
for (; i != end && pos < size(); ++i) {
set(pos, *i);
}
CAPNPROTO_INLINE_DPRECOND(pos == size() && i == end,
"List::copyFrom() argument had different size.");
}
void copyFrom(std::initializer_list<T> other) {
CAPNPROTO_INLINE_DPRECOND(other.size() == size(),
"List::copyFrom() argument had different size.");
for (uint i = 0; i < other.size(); i++) {
set(i, other.begin()[i]);
}
}
private: private:
internal::ListBuilder builder; internal::ListBuilder builder;
}; };
...@@ -308,6 +296,10 @@ struct List<T, Kind::STRUCT> { ...@@ -308,6 +296,10 @@ struct List<T, Kind::STRUCT> {
private: private:
internal::ListReader reader; internal::ListReader reader;
template <typename U, Kind K>
friend struct internal::PointerHelpers;
template <typename U, Kind K>
friend struct List;
}; };
class Builder { class Builder {
...@@ -317,20 +309,23 @@ struct List<T, Kind::STRUCT> { ...@@ -317,20 +309,23 @@ struct List<T, Kind::STRUCT> {
Builder() = default; Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {} inline explicit Builder(internal::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 uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) const { inline typename T::Builder operator[](uint index) const {
return typename T::Builder(builder.getStructElement(index * ELEMENTS)); return typename T::Builder(builder.getStructElement(index * ELEMENTS));
} }
// There are no init() or set() methods for lists of structs because the elements of the list
// are inlined and are initialized when the list is initialized. This means that init() would
// be redundant, and set() would risk data loss if the input struct were from a newer version
// of teh protocol.
typedef internal::IndexingIterator<Builder, typename T::Builder> iterator; typedef internal::IndexingIterator<Builder, typename T::Builder> iterator;
inline iterator begin() const { return iterator(this, 0); } inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); } inline iterator end() const { return iterator(this, size()); }
template <typename Other>
void copyFrom(const Other& other);
void copyFrom(std::initializer_list<typename T::Reader> other);
// TODO
private: private:
internal::ListBuilder builder; internal::ListBuilder builder;
}; };
...@@ -391,6 +386,10 @@ struct List<List<T>, Kind::LIST> { ...@@ -391,6 +386,10 @@ struct List<List<T>, Kind::LIST> {
private: private:
internal::ListReader reader; internal::ListReader reader;
template <typename U, Kind K>
friend struct internal::PointerHelpers;
template <typename U, Kind K>
friend struct List;
}; };
class Builder { class Builder {
...@@ -400,6 +399,9 @@ struct List<List<T>, Kind::LIST> { ...@@ -400,6 +399,9 @@ struct List<List<T>, Kind::LIST> {
Builder() = default; Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {} inline explicit Builder(internal::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 uint size() const { return builder.size() / ELEMENTS; }
inline typename List<T>::Builder operator[](uint index) const { inline typename List<T>::Builder operator[](uint index) const {
return typename List<T>::Builder(List<T>::getAsElementOf(builder, index)); return typename List<T>::Builder(List<T>::getAsElementOf(builder, index));
...@@ -407,16 +409,21 @@ struct List<List<T>, Kind::LIST> { ...@@ -407,16 +409,21 @@ struct List<List<T>, Kind::LIST> {
inline typename List<T>::Builder init(uint index, uint size) { inline typename List<T>::Builder init(uint index, uint size) {
return typename List<T>::Builder(List<T>::initAsElementOf(builder, index, size)); return typename List<T>::Builder(List<T>::initAsElementOf(builder, index, size));
} }
inline void set(uint index, typename List<T>::Reader value) {
builder.setListElement(index * ELEMENTS, value.reader);
}
void set(uint index, std::initializer_list<ReaderFor<T>> value) {
auto l = init(index, value.size());
uint i = 0;
for (auto& element: value) {
l.set(i++, element);
}
}
typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator; typedef internal::IndexingIterator<Builder, typename List<T>::Builder> iterator;
inline iterator begin() const { return iterator(this, 0); } inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); } inline iterator end() const { return iterator(this, size()); }
template <typename Other>
void copyFrom(const Other& other);
void copyFrom(std::initializer_list<typename List<T>::Reader> other);
// TODO
private: private:
internal::ListBuilder builder; internal::ListBuilder builder;
}; };
...@@ -475,6 +482,10 @@ struct List<T, Kind::BLOB> { ...@@ -475,6 +482,10 @@ struct List<T, Kind::BLOB> {
private: private:
internal::ListReader reader; internal::ListReader reader;
template <typename U, Kind K>
friend struct internal::PointerHelpers;
template <typename U, Kind K>
friend struct List;
}; };
class Builder { class Builder {
...@@ -484,6 +495,9 @@ struct List<T, Kind::BLOB> { ...@@ -484,6 +495,9 @@ struct List<T, Kind::BLOB> {
Builder() = default; Builder() = default;
inline explicit Builder(internal::ListBuilder builder): builder(builder) {} inline explicit Builder(internal::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 uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) const { inline typename T::Builder operator[](uint index) const {
return builder.getBlobElement<T>(index * ELEMENTS); return builder.getBlobElement<T>(index * ELEMENTS);
...@@ -499,25 +513,6 @@ struct List<T, Kind::BLOB> { ...@@ -499,25 +513,6 @@ struct List<T, Kind::BLOB> {
inline iterator begin() const { return iterator(this, 0); } inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); } inline iterator end() const { return iterator(this, size()); }
template <typename Other>
void copyFrom(const Other& other) {
auto i = other.begin();
auto end = other.end();
uint pos = 0;
for (; i != end && pos < size(); ++i) {
set(pos, *i);
}
CAPNPROTO_INLINE_DPRECOND(pos == size() && i == end,
"List::copyFrom() argument had different size.");
}
void copyFrom(std::initializer_list<typename T::Reader> other) {
CAPNPROTO_INLINE_DPRECOND(other.size() == size(),
"List::copyFrom() argument had different size.");
for (uint i = 0; i < other.size(); i++) {
set(i, other.begin()[i]);
}
}
private: private:
internal::ListBuilder builder; internal::ListBuilder builder;
}; };
......
...@@ -95,6 +95,12 @@ internal::StructBuilder MessageBuilder::initRoot(internal::StructSize size) { ...@@ -95,6 +95,12 @@ internal::StructBuilder MessageBuilder::initRoot(internal::StructSize size) {
rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), size); rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), size);
} }
void MessageBuilder::setRootInternal(internal::StructReader reader) {
internal::SegmentBuilder* rootSegment = getRootSegment();
internal::StructBuilder::setRoot(
rootSegment, rootSegment->getPtrUnchecked(0 * WORDS), reader);
}
internal::StructBuilder MessageBuilder::getRoot(internal::StructSize size) { internal::StructBuilder MessageBuilder::getRoot(internal::StructSize size) {
internal::SegmentBuilder* rootSegment = getRootSegment(); internal::SegmentBuilder* rootSegment = getRootSegment();
return internal::StructBuilder::getRoot( return internal::StructBuilder::getRoot(
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "type-safety.h" #include "type-safety.h"
#include "layout.h" #include "layout.h"
#include "list.h" // TODO(cleanup): For FromReader. Move elsewhere?
#ifndef CAPNPROTO_MESSAGE_H_ #ifndef CAPNPROTO_MESSAGE_H_
#define CAPNPROTO_MESSAGE_H_ #define CAPNPROTO_MESSAGE_H_
...@@ -133,6 +135,10 @@ public: ...@@ -133,6 +135,10 @@ public:
typename RootType::Builder initRoot(); typename RootType::Builder initRoot();
// Initialize the root struct of the message as the given struct type. // Initialize the root struct of the message as the given struct type.
template <typename Reader>
void setRoot(Reader&& value);
// Set the root struct to a deep copy of the given struct.
template <typename RootType> template <typename RootType>
typename RootType::Builder getRoot(); typename RootType::Builder getRoot();
// Get the root struct of the message, interpreting it as the given struct type. // Get the root struct of the message, interpreting it as the given struct type.
...@@ -162,6 +168,7 @@ private: ...@@ -162,6 +168,7 @@ private:
internal::BuilderArena* arena() { return reinterpret_cast<internal::BuilderArena*>(arenaSpace); } internal::BuilderArena* arena() { return reinterpret_cast<internal::BuilderArena*>(arenaSpace); }
internal::SegmentBuilder* getRootSegment(); internal::SegmentBuilder* getRootSegment();
internal::StructBuilder initRoot(internal::StructSize size); internal::StructBuilder initRoot(internal::StructSize size);
void setRootInternal(internal::StructReader reader);
internal::StructBuilder getRoot(internal::StructSize size); internal::StructBuilder getRoot(internal::StructSize size);
}; };
...@@ -301,6 +308,13 @@ inline typename RootType::Builder MessageBuilder::initRoot() { ...@@ -301,6 +308,13 @@ inline typename RootType::Builder MessageBuilder::initRoot() {
return typename RootType::Builder(initRoot(internal::structSize<RootType>())); return typename RootType::Builder(initRoot(internal::structSize<RootType>()));
} }
template <typename Reader>
inline void MessageBuilder::setRoot(Reader&& value) {
typedef FromReader<Reader> RootType;
static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type.");
setRootInternal(value._reader);
}
template <typename RootType> template <typename RootType>
inline typename RootType::Builder MessageBuilder::getRoot() { inline typename RootType::Builder MessageBuilder::getRoot() {
static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type."); static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type.");
......
...@@ -355,16 +355,16 @@ void genericInitListDefaults(Builder builder) { ...@@ -355,16 +355,16 @@ void genericInitListDefaults(Builder builder) {
{ {
auto l = lists.initInt32ListList(3); auto l = lists.initInt32ListList(3);
l.init(0, 3).copyFrom({1, 2, 3}); l.set(0, {1, 2, 3});
l.init(1, 2).copyFrom({4, 5}); l.set(1, {4, 5});
l.init(2, 1).copyFrom({12341234}); l.set(2, {12341234});
} }
{ {
auto l = lists.initTextListList(3); auto l = lists.initTextListList(3);
l.init(0, 2).copyFrom({"foo", "bar"}); l.set(0, {"foo", "bar"});
l.init(1, 1).copyFrom({"baz"}); l.set(1, {"baz"});
l.init(2, 2).copyFrom({"qux", "corge"}); l.set(2, {"qux", "corge"});
} }
{ {
......
...@@ -174,6 +174,9 @@ private: ...@@ -174,6 +174,9 @@ private:
::capnproto::internal::StructReader _reader; ::capnproto::internal::StructReader _reader;
template <typename T, ::capnproto::Kind k> template <typename T, ::capnproto::Kind k>
friend struct ::capnproto::ToDynamic_; friend struct ::capnproto::ToDynamic_;
template <typename T, ::capnproto::Kind k>
friend struct ::capnproto::internal::PointerHelpers;
friend struct ::capnproto::MessageBuilder;
}; };
{{! ------------------------------------------------------------------------------------------- }} {{! ------------------------------------------------------------------------------------------- }}
...@@ -207,10 +210,10 @@ public: ...@@ -207,10 +210,10 @@ public:
{{^fieldIsGenericObject}} {{^fieldIsGenericObject}}
inline {{fieldType}}::Builder get{{fieldTitleCase}}(); inline {{fieldType}}::Builder get{{fieldTitleCase}}();
inline void set{{fieldTitleCase}}({{fieldType}}::Reader other); inline void set{{fieldTitleCase}}({{fieldType}}::Reader other);
{{#fieldIsList}} {{#fieldIsNonStructList}}
inline void set{{fieldTitleCase}}( inline void set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementReaderType}}> other); std::initializer_list<{{fieldElementReaderType}}> other);
{{/fieldIsList}} {{/fieldIsNonStructList}}
{{#fieldIsListOrBlob}} {{#fieldIsListOrBlob}}
inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size); inline {{fieldType}}::Builder init{{fieldTitleCase}}(unsigned int size);
{{/fieldIsListOrBlob}} {{/fieldIsListOrBlob}}
...@@ -224,6 +227,8 @@ public: ...@@ -224,6 +227,8 @@ public:
template <typename T, typename Param> inline typename T::Builder template <typename T, typename Param> inline typename T::Builder
get{{fieldTitleCase}}(Param&& param); get{{fieldTitleCase}}(Param&& param);
template <typename T> inline void set{{fieldTitleCase}}(typename T::Reader value); template <typename T> inline void set{{fieldTitleCase}}(typename T::Reader value);
template <typename T, typename U> inline void
set{{fieldTitleCase}}(std::initializer_list<U> value);
template <typename T, typename... Params> inline typename T::Builder template <typename T, typename... Params> inline typename T::Builder
init{{fieldTitleCase}}(Params&&... params); init{{fieldTitleCase}}(Params&&... params);
{{/fieldIsGenericObject}} {{/fieldIsGenericObject}}
...@@ -325,7 +330,7 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}}::Read ...@@ -325,7 +330,7 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}}::Read
_builder, {{fieldOffset}} * ::capnproto::POINTERS, value); _builder, {{fieldOffset}} * ::capnproto::POINTERS, value);
} }
{{#fieldIsList}} {{#fieldIsNonStructList}}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
std::initializer_list<{{fieldElementReaderType}}> value) { std::initializer_list<{{fieldElementReaderType}}> value) {
{{#fieldUnion}} {{#fieldUnion}}
...@@ -336,7 +341,7 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}( ...@@ -336,7 +341,7 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(
_builder, {{fieldOffset}} * ::capnproto::POINTERS, value); _builder, {{fieldOffset}} * ::capnproto::POINTERS, value);
} }
{{/fieldIsList}} {{/fieldIsNonStructList}}
{{#fieldIsListOrBlob}} {{#fieldIsListOrBlob}}
inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(unsigned int size) { inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(unsigned int size) {
{{#fieldUnion}} {{#fieldUnion}}
...@@ -413,6 +418,16 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(typename T::Reader ...@@ -413,6 +418,16 @@ inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(typename T::Reader
_builder, {{fieldOffset}} * ::capnproto::POINTERS, value); _builder, {{fieldOffset}} * ::capnproto::POINTERS, value);
} }
template <typename T, typename U>
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}(std::initializer_list<U> value) {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
::capnproto::internal::PointerHelpers<T>::set(
_builder, {{fieldOffset}} * ::capnproto::POINTERS, value);
}
template <typename T, typename... Params> template <typename T, typename... Params>
inline typename T::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(Params&&... params) { inline typename T::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(Params&&... params) {
{{#fieldUnion}} {{#fieldUnion}}
......
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