implement MessageBuilder.unsafeConstructFromMessageReader()

This commit is contained in:
David Renshaw 2021-05-24 13:06:42 -04:00
parent a078df7e4d
commit a55b869305
3 changed files with 41 additions and 1 deletions

View file

@ -64,6 +64,30 @@ public final class BuilderArena implements Arena {
this.allocator = allocator;
}
/**
* Constructs a BuilderArena from a ReaderArena and uses the size of the largest segment
* as the next allocation size.
*/
BuilderArena(ReaderArena arena) {
this.segments = new ArrayList<SegmentBuilder>();
int largestSegment = SUGGESTED_FIRST_SEGMENT_WORDS*Constants.BYTES_PER_WORD;
for (int ii = 0; ii < arena.segments.size(); ++ii) {
SegmentReader segment = arena.segments.get(ii);
SegmentBuilder segmentBuilder = new SegmentBuilder(segment.buffer, this);
segmentBuilder.id = ii;
segmentBuilder.pos = segmentBuilder.capacity(); // buffer is pre-filled
segments.add(segmentBuilder);
// Find the largest segment for the allocation strategy.
largestSegment = Math.max(largestSegment, segment.buffer.capacity());
}
DefaultAllocator defaultAllocator = new DefaultAllocator(SUGGESTED_ALLOCATION_STRATEGY);
// Use largest segment as next size.
defaultAllocator.setNextAllocationSizeBytes(largestSegment);
this.allocator = defaultAllocator;
}
@Override
public final SegmentReader tryGetSegment(int id) {
return this.segments.get(id);

View file

@ -71,6 +71,22 @@ public final class MessageBuilder {
this.arena = new BuilderArena(new DefaultAllocator(), firstSegment);
}
/**
* Constructs a MessageBuilder from a MessageReader. This constructor is private
* because it is unsafe. To use it, you must call `unsafeConstructFromMessageReader()`.
*/
private MessageBuilder(MessageReader messageReader) {
this.arena = new BuilderArena(messageReader.arena);
}
/**
* Constructs a MessageBuilder from a MessageReader without copying the segments.
* This method should only be used on trusted data. Otherwise you may observe infinite
* loops or large memory allocations or index-out-of-bounds errors.
*/
public static MessageBuilder unsafeConstructFromMessageReader(MessageReader messageReader) {
return new MessageBuilder(messageReader);
}
private AnyPointer.Builder getRootInternal() {
if (this.arena.segments.isEmpty()) {

View file

@ -35,7 +35,7 @@ public final class SegmentBuilder extends SegmentReader {
}
// the total number of words the buffer can hold
private final int capacity() {
final int capacity() {
this.buffer.rewind();
return this.buffer.remaining() / 8;
}