followBuilderFars. does not pass unit tests yet

This commit is contained in:
David Renshaw 2014-06-16 19:46:33 -04:00
parent 449ef9f503
commit df2233a52b
4 changed files with 78 additions and 24 deletions

View file

@ -14,4 +14,11 @@ class EncodingSuite extends FunSuite {
TestUtil.checkTestMessage(allTypes); TestUtil.checkTestMessage(allTypes);
} }
test("AllTypesMultiSegment") {
val message = new MessageBuilder(5, BuilderArena.AllocationStrategy.FIXED_SIZE);
val allTypes = message.initRoot(TestAllTypes.Builder.factory);
TestUtil.initTestMessage(allTypes);
//TestUtil.checkTestMessage(allTypes);
}
} }

View file

@ -36,7 +36,7 @@ public final class BuilderArena implements Arena {
throw new Error("unimplemented"); throw new Error("unimplemented");
} }
public SegmentBuilder getSegment(int id) { public SegmentBuilder getSegment(int id) {
throw new Error("unimplemented"); return this.segments.get(id);
} }
public static class AllocateResult { public static class AllocateResult {

View file

@ -3,7 +3,19 @@ package org.capnproto;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
final class FarPointer { final class FarPointer {
public static void set(ByteBuffer buffer, int offset, int segmentId) { public static int getSegmentId(long ref) {
return WirePointer.upper32Bits(ref);
}
public static int positionInSegment(long ref) {
return WirePointer.offsetAndKind(ref) >>> 3;
}
public static boolean isDoubleFar(long ref) {
return ((WirePointer.offsetAndKind(ref) >>> 2) & 1) != 0;
}
public static void setSegmentId(ByteBuffer buffer, int offset, int segmentId) {
buffer.putInt(8 * offset + 4, segmentId); buffer.putInt(8 * offset + 4, segmentId);
} }
} }

View file

@ -39,7 +39,7 @@ final class WireHelpers {
//# Set up the original pointer to be a far pointer to //# Set up the original pointer to be a far pointer to
//# the new segment. //# the new segment.
WirePointer.setKindAndTarget(segment.buffer, refOffset, WirePointer.FAR, allocation.offset); WirePointer.setKindAndTarget(segment.buffer, refOffset, WirePointer.FAR, allocation.offset);
FarPointer.set(segment.buffer, refOffset, allocation.segment.id); FarPointer.setSegmentId(segment.buffer, refOffset, allocation.segment.id);
//# Initialize the landing pad to indicate that the //# Initialize the landing pad to indicate that the
//# data immediately follows the pad. //# data immediately follows the pad.
@ -56,6 +56,46 @@ final class WireHelpers {
} }
} }
static class FollowBuilderFarsResult {
public final int ptr;
public final long ref;
public final SegmentBuilder segment;
FollowBuilderFarsResult(int ptr, long ref, SegmentBuilder segment) {
this.ptr = ptr; this.ref = ref; this.segment = segment;
}
}
public static FollowBuilderFarsResult followBuilderFars(long ref, int refTarget,
SegmentBuilder segment) {
//# If `ref` is a far pointer, follow it. On return, `ref` will
//# have been updated to point at a WirePointer that contains
//# the type information about the target object, and a pointer
//# to the object contents is returned. The caller must NOT use
//# `ref->target()` as this may or may not actually return a
//# valid pointer. `segment` is also updated to point at the
//# segment which actually contains the object.
//#
//# If `ref` is not a far pointer, this simply returns
//# `refTarget`. Usually, `refTarget` should be the same as
//# `ref->target()`, but may not be in cases where `ref` is
//# only a tag.
if (WirePointer.kind(ref) == WirePointer.FAR) {
SegmentBuilder resultSegment = segment.getArena().getSegment(FarPointer.getSegmentId(ref));
int padOffset = FarPointer.positionInSegment(ref);
long pad = WirePointer.get(resultSegment.buffer, padOffset);
if (! FarPointer.isDoubleFar(ref)) {
return new FollowBuilderFarsResult(WirePointer.target(padOffset, pad), pad, resultSegment);
}
throw new Error("unimplemented");
} else {
return new FollowBuilderFarsResult(refTarget, ref, segment);
}
}
public static StructBuilder initStructPointer(int refOffset, public static StructBuilder initStructPointer(int refOffset,
SegmentBuilder segment, SegmentBuilder segment,
StructSize size) { StructSize size) {
@ -74,20 +114,17 @@ final class WireHelpers {
if (WirePointer.isNull(ref)) { if (WirePointer.isNull(ref)) {
return initStructPointer(refOffset, segment, size); return initStructPointer(refOffset, segment, size);
} }
long oldRef = ref; FollowBuilderFarsResult resolved = followBuilderFars(ref, target, segment);
SegmentBuilder oldSegment = segment;
// TODO follow fars.
int oldPtrOffset = target;
short oldDataSize = StructPointer.dataSize(WirePointer.structPointer(oldRef)); short oldDataSize = StructPointer.dataSize(WirePointer.structPointer(resolved.ref));
short oldPointerCount = StructPointer.ptrCount(WirePointer.structPointer(oldRef)); short oldPointerCount = StructPointer.ptrCount(WirePointer.structPointer(resolved.ref));
int oldPointerSectionOffset = oldPtrOffset + oldDataSize; int oldPointerSectionOffset = resolved.ptr + oldDataSize;
if (oldDataSize < size.data || oldPointerCount < size.pointers) { if (oldDataSize < size.data || oldPointerCount < size.pointers) {
throw new Error("unimplemented"); throw new Error("unimplemented");
} else { } else {
return new StructBuilder(oldSegment, oldPtrOffset * 8, return new StructBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD,
oldPointerSectionOffset, oldDataSize * 64, oldPointerSectionOffset, oldDataSize * Constants.BITS_PER_WORD,
oldPointerCount, (byte)0); oldPointerCount, (byte)0);
} }
@ -163,15 +200,13 @@ final class WireHelpers {
//# non-struct lists, and there is no allowed upgrade path *to* //# non-struct lists, and there is no allowed upgrade path *to*
//# a non-struct list, only *from* them. //# a non-struct list, only *from* them.
long ref = origRef; FollowBuilderFarsResult resolved = followBuilderFars(origRef, origRefTarget, origSegment);
SegmentBuilder segment = origSegment;
int ptr = origRefTarget; // TODO follow fars.
if (WirePointer.kind(ref) != WirePointer.LIST) { if (WirePointer.kind(resolved.ref) != WirePointer.LIST) {
throw new DecodeException("Called getList{Field,Element}() but existing pointer is not a list"); throw new DecodeException("Called getList{Field,Element}() but existing pointer is not a list");
} }
byte oldSize = ListPointer.elementSize(WirePointer.listPointer(ref)); byte oldSize = ListPointer.elementSize(WirePointer.listPointer(resolved.ref));
if (oldSize == FieldSize.INLINE_COMPOSITE) { if (oldSize == FieldSize.INLINE_COMPOSITE) {
//# The existing element size is InlineComposite, which //# The existing element size is InlineComposite, which
@ -196,8 +231,8 @@ final class WireHelpers {
int step = dataSize + pointerCount * Constants.BITS_PER_POINTER; int step = dataSize + pointerCount * Constants.BITS_PER_POINTER;
return new ListBuilder(segment, ptr * Constants.BYTES_PER_WORD, return new ListBuilder(resolved.segment, resolved.ptr * Constants.BYTES_PER_WORD,
ListPointer.elementCount(WirePointer.listPointer(ref)), ListPointer.elementCount(WirePointer.listPointer(resolved.ref)),
step, dataSize, (short) pointerCount); step, dataSize, (short) pointerCount);
} }
} }
@ -241,20 +276,20 @@ final class WireHelpers {
} }
int refTarget = WirePointer.target(refOffset, ref); int refTarget = WirePointer.target(refOffset, ref);
int ptr = refTarget; FollowBuilderFarsResult resolved = followBuilderFars(ref, refTarget, segment);
if (WirePointer.kind(ref) != WirePointer.LIST) { if (WirePointer.kind(resolved.ref) != WirePointer.LIST) {
throw new DecodeException("Called getText{Field,Element} but existing pointer is not a list."); throw new DecodeException("Called getText{Field,Element} but existing pointer is not a list.");
} }
if (ListPointer.elementSize(WirePointer.listPointer(ref)) != FieldSize.BYTE) { if (ListPointer.elementSize(WirePointer.listPointer(resolved.ref)) != FieldSize.BYTE) {
throw new DecodeException( throw new DecodeException(
"Called getText{Field,Element} but existing list pointer is not byte-sized."); "Called getText{Field,Element} but existing list pointer is not byte-sized.");
} }
//# Subtract 1 from the size for the NUL terminator. //# Subtract 1 from the size for the NUL terminator.
return new Text.Builder(segment.buffer, ptr * 8, return new Text.Builder(resolved.segment.buffer, resolved.ptr * Constants.BYTES_PER_WORD,
ListPointer.elementCount(WirePointer.listPointer(ref)) - 1); ListPointer.elementCount(WirePointer.listPointer(resolved.ref)) - 1);
} }