implement StructList.Builder.setWithCaveats()

This commit is contained in:
David Renshaw 2019-03-23 10:32:01 -04:00
parent 45fd638c7c
commit c6762ff0f7
3 changed files with 98 additions and 1 deletions

View file

@ -817,6 +817,30 @@ class EncodingSuite extends FunSuite {
}
}
test("setWithCaveats") {
val builder = new MessageBuilder()
val root = builder.initRoot(TestAllTypes.factory)
val list = root.initStructList(2)
{
val message1 = new MessageBuilder()
val root1 = message1.initRoot(TestAllTypes.factory)
root1.setInt8Field(11)
list.setWithCaveats(TestAllTypes.factory, 0, root1.asReader())
}
{
val message2 = new MessageBuilder()
val root2 = message2.initRoot(TestAllTypes.factory)
TestUtil.initTestMessage(root2)
list.setWithCaveats(TestAllTypes.factory, 1, root2.asReader())
}
val listReader = list.asReader(TestAllTypes.factory)
listReader.get(0).getInt8Field() should equal (11)
TestUtil.checkTestMessage(listReader.get(1))
}
// to debug, do this:
//Serialize.write((new java.io.FileOutputStream("/Users/dwrensha/Desktop/test.dat")).getChannel(),
// message)

View file

@ -197,4 +197,63 @@ public class StructBuilder {
protected final <Builder, Reader> void _setPointerField(SetPointerBuilder<Builder, Reader> factory, int index, Reader value) {
factory.setPointerBuilder(this.segment, this.pointers + index, value);
}
protected final void _copyContentFrom(StructReader other) {
// Determine the amount of data the builders have in common.
int sharedDataSize = java.lang.Math.min(this.dataSize, other.dataSize);
int sharedPointerCount = java.lang.Math.min(this.pointerCount, other.pointerCount);
if (other.segment == this.segment &&
((sharedDataSize > 0 && other.data == this.data) ||
(sharedPointerCount > 0 && other.pointers == this.pointers))) {
// At least one of the section pointers is pointing to ourself. Verify that the other is too
// (but ignore empty sections).
if ((sharedDataSize == 0 || other.data == this.data) &&
(sharedPointerCount == 0 || other.pointers == this.pointers)) {
throw new Error("Only one of the section pointers is pointing to ourself");
}
// So `other` appears to be a reader for this same struct. No copying is needed.
return;
}
if (this.dataSize > sharedDataSize) {
// Since the target is larger than the source, make sure to zero out the extra bits that the
// source doesn't have.
if (this.dataSize == 1) {
this._setBooleanField(0, false);
} else {
int unshared = this.data + sharedDataSize / Constants.BITS_PER_BYTE;
WireHelpers.memset(this.segment.buffer,
unshared,
(byte)0,
(this.dataSize - sharedDataSize) / Constants.BITS_PER_BYTE);
}
}
// Copy over the shared part.
if (sharedDataSize == 1) {
this._setBooleanField(0, other._getBooleanField(0));
} else {
WireHelpers.memcpy(this.segment.buffer,
this.data,
other.segment.buffer,
other.data,
sharedDataSize / Constants.BITS_PER_BYTE);
}
// Zero out all pointers in the target.
for (int ii = 0; ii < this.pointerCount; ++ii) {
WireHelpers.zeroObject(this.segment, this.pointers + ii);
}
this.segment.buffer.putLong(this.pointers * Constants.BYTES_PER_WORD, 0);
for (int ii = 0; ii < sharedPointerCount; ++ii) {
WireHelpers.copyPointer(this.segment,
this.pointers + ii,
other.segment,
other.pointers + ii,
other.nestingLimit);
}
}
}

View file

@ -118,7 +118,7 @@ public final class StructList {
}
}
public static final class Builder<T> extends ListBuilder implements Iterable<T> {
public static final class Builder<T extends StructBuilder> extends ListBuilder implements Iterable<T> {
public final StructBuilder.Factory<T> factory;
public Builder(StructBuilder.Factory<T> factory,
@ -134,6 +134,20 @@ public final class StructList {
}
// TODO: rework generics so that we don't need this factory parameter
public final <U extends StructReader> void setWithCaveats(StructFactory<T, U> factory,
int index,
U value) {
this._getStructElement(this.factory, index)._copyContentFrom(value);
}
/**
* Sets the list element, with the following limitation based on the fact that structs in a
* struct list are allocated inline: if the source struct is larger than the target struct
* (as can happen if it was created with a newer version of the schema), then it will be
* truncated, losing fields.
*
* TODO: rework generics, so that we don't need this factory parameter
*/
public final <U extends StructReader> Reader<U> asReader(StructFactory<T, U> factory) {
return new Reader(factory,
this.segment, this.ptr, this.elementCount, this.step,