BuilderArena.allocate

This commit is contained in:
David Renshaw 2014-06-15 16:38:26 -04:00
parent 0c56671f3c
commit b63cfb11f1
6 changed files with 54 additions and 17 deletions

View file

@ -2,7 +2,7 @@ package org.capnproto;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Vector;
import java.util.ArrayList;
public final class BuilderArena implements Arena {
@ -15,19 +15,18 @@ public final class BuilderArena implements Arena {
public static final AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY =
AllocationStrategy.GROW_HEURISTICALLY;
// Maybe this should be ArrayList?
public final Vector<SegmentBuilder> segments;
public final ArrayList<SegmentBuilder> segments;
public int nextSize;
public final AllocationStrategy allocationStrategy;
public BuilderArena(int firstSegmentSizeWords, AllocationStrategy allocationStrategy) {
this.segments = new Vector<SegmentBuilder>();
this.segments = new ArrayList<SegmentBuilder>();
this.nextSize = firstSegmentSizeWords;
this.allocationStrategy = allocationStrategy;
SegmentBuilder segment0 = new SegmentBuilder(
ByteBuffer.allocate(firstSegmentSizeWords * Constants.BYTES_PER_WORD));
ByteBuffer.allocate(firstSegmentSizeWords * Constants.BYTES_PER_WORD), this);
segment0.buffer.mark();
segment0.buffer.order(ByteOrder.LITTLE_ENDIAN);
this.segments.add(segment0);
@ -42,7 +41,10 @@ public final class BuilderArena implements Arena {
public static class AllocateResult {
public final SegmentBuilder segment;
// offset to the beginning the of allocated memory
public final int offset;
public AllocateResult(SegmentBuilder segment, int offset) {
this.segment = segment;
this.offset = offset;
@ -50,7 +52,23 @@ public final class BuilderArena implements Arena {
}
public AllocateResult allocate(int amount) {
throw new Error("unimplemented");
int len = this.segments.size();
// we allocate the first segment in the constructor.
int result = this.segments.get(len - 1).allocate(amount);
if (result != SegmentBuilder.FAILED_ALLOCATION) {
return new AllocateResult(this.segments.get(len - 1), result);
}
SegmentBuilder newSegment = new SegmentBuilder(
ByteBuffer.allocate(amount * Constants.BYTES_PER_WORD),
this);
newSegment.buffer.mark();
newSegment.buffer.order(ByteOrder.LITTLE_ENDIAN);
this.segments.add(newSegment);
return new AllocateResult(newSegment, newSegment.allocate(amount));
}
public final ByteBuffer[] getSegmentsForOutput() {

View file

@ -10,7 +10,7 @@ public final class MessageReader {
}
public <T> T getRoot(FromStructReader<T> factory) {
SegmentReader segment = new SegmentReader(this.segmentSlices[0]);
SegmentReader segment = new SegmentReader(this.segmentSlices[0], new ReaderArena());
PointerReader pointerReader = PointerReader.getRoot(segment, 0,
0x7fffffff /* XXX */);
AnyPointer.Reader any = new AnyPointer.Reader(pointerReader);

View file

@ -3,12 +3,13 @@ package org.capnproto;
import java.nio.ByteBuffer;
public final class SegmentBuilder extends SegmentReader {
public static final int FAILED_ALLOCATION = -1;
public int pos = 0; // in words
public SegmentBuilder(ByteBuffer buf) {
super(buf);
public SegmentBuilder(ByteBuffer buf, Arena arena) {
super(buf, arena);
}
// the total number of words the buffer can hold
@ -22,10 +23,14 @@ public final class SegmentBuilder extends SegmentReader {
return this.pos;
}
/**
/*
Allocate `amount` words.
*/
public final int allocate(int amount) {
if (amount < 0) {
throw new InternalError("tried to allocate a negative number of words");
}
if (amount > this.capacity() - this.currentSize()) {
return FAILED_ALLOCATION; // no space left;
} else {
@ -34,4 +39,8 @@ public final class SegmentBuilder extends SegmentReader {
return result;
}
}
public final BuilderArena getArena() {
return (BuilderArena)this.arena;
}
}

View file

@ -7,7 +7,10 @@ public class SegmentReader {
// invariant: buffer's mark is at its beginning.
final ByteBuffer buffer;
public SegmentReader(ByteBuffer buffer) {
final Arena arena;
public SegmentReader(ByteBuffer buffer, Arena arena) {
this.buffer = buffer;
this.arena = arena;
}
}

View file

@ -18,15 +18,19 @@ final class WireHelpers {
// TODO check for nullness, amount == 0 case.
int allocation = segment.allocate(amount);
if (allocation == SegmentBuilder.FAILED_ALLOCATION) {
int ptr = segment.allocate(amount);
if (ptr == SegmentBuilder.FAILED_ALLOCATION) {
//# Need to allocate in a new segment. We'll need to
//# allocate an extra pointer worth of space to act as
//# the landing pad for a far pointer.
int amountPlusRef = amount + Constants.POINTER_SIZE_IN_WORDS;
BuilderArena.AllocateResult allocation = segment.getArena().allocate(amountPlusRef);
throw new Error("unimplemented");
} else {
WirePointer.setKindAndTarget(segment.buffer, refOffset, kind, allocation);
return allocation;
WirePointer.setKindAndTarget(segment.buffer, refOffset, kind, ptr);
return ptr;
}
}

View file

@ -13,7 +13,7 @@ class LayoutSuite extends FunSuite {
val buffer = java.nio.ByteBuffer.wrap(data);
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
val pointerReader = new PointerReader(new SegmentReader(buffer), 0, 0x7fffffff);
val pointerReader = new PointerReader(new SegmentReader(buffer, new ReaderArena()), 0, 0x7fffffff);
val reader = pointerReader.getStruct();
assert(reader.getLongField(0) === 0xefcdab8967452301L);
@ -91,7 +91,10 @@ class LayoutSuite extends FunSuite {
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
buffer.mark();
val pointerBuilder = PointerBuilder.getRoot(new SegmentBuilder(buffer), 0);
val pointerBuilder = PointerBuilder.getRoot(
new SegmentBuilder(buffer, new BuilderArena(BuilderArena.SUGGESTED_FIRST_SEGMENT_WORDS,
BuilderArena.SUGGESTED_ALLOCATION_STRATEGY)),
0);
val builder = pointerBuilder.initStruct(new StructSize(2, 4, FieldSize.INLINE_COMPOSITE));
setupStruct(builder);