followBuilderFars. does not pass unit tests yet
This commit is contained in:
parent
449ef9f503
commit
df2233a52b
4 changed files with 78 additions and 24 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue