2020-08-28 14:02:51 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2020 The Netty Project
|
|
|
|
*
|
|
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
|
|
* with the License. You may obtain a copy of the License at:
|
|
|
|
*
|
2020-10-28 14:38:14 +01:00
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
2020-08-28 14:02:51 +02:00
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
|
|
|
*/
|
2020-11-17 15:53:40 +01:00
|
|
|
package io.netty.buffer.api.memseg;
|
2020-07-24 19:38:48 +02:00
|
|
|
|
2021-02-17 13:54:11 +01:00
|
|
|
import io.netty.buffer.ByteBuf;
|
2021-02-12 18:22:07 +01:00
|
|
|
import io.netty.buffer.api.BufferAllocator;
|
2021-05-20 18:57:31 +02:00
|
|
|
import io.netty.buffer.api.adaptor.BufferIntegratable;
|
|
|
|
import io.netty.buffer.api.adaptor.ByteBufAdaptor;
|
|
|
|
import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
|
|
|
|
import io.netty.buffer.api.internal.ArcDrop;
|
|
|
|
import io.netty.buffer.api.internal.Statics;
|
2020-11-17 15:53:40 +01:00
|
|
|
import io.netty.buffer.api.AllocatorControl;
|
2021-02-12 18:22:07 +01:00
|
|
|
import io.netty.buffer.api.Buffer;
|
2020-12-02 14:29:40 +01:00
|
|
|
import io.netty.buffer.api.ByteCursor;
|
2021-02-12 18:28:05 +01:00
|
|
|
import io.netty.buffer.api.ReadableComponent;
|
|
|
|
import io.netty.buffer.api.ReadableComponentProcessor;
|
|
|
|
import io.netty.buffer.api.WritableComponent;
|
|
|
|
import io.netty.buffer.api.WritableComponentProcessor;
|
2020-11-17 15:53:40 +01:00
|
|
|
import io.netty.buffer.api.Drop;
|
|
|
|
import io.netty.buffer.api.Owned;
|
2021-05-26 17:13:29 +02:00
|
|
|
import io.netty.buffer.api.internal.ResourceSupport;
|
2021-05-28 17:10:46 +02:00
|
|
|
import io.netty.util.IllegalReferenceCountException;
|
2020-07-24 19:38:48 +02:00
|
|
|
import jdk.incubator.foreign.MemorySegment;
|
2021-04-07 14:28:05 +02:00
|
|
|
import jdk.incubator.foreign.ResourceScope;
|
2020-07-24 19:38:48 +02:00
|
|
|
|
2020-10-30 14:39:50 +01:00
|
|
|
import java.nio.ByteBuffer;
|
2020-10-06 15:54:48 +02:00
|
|
|
import java.nio.ByteOrder;
|
|
|
|
|
2021-05-28 15:13:16 +02:00
|
|
|
import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
|
|
|
|
import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
|
2020-11-20 14:01:14 +01:00
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getByteAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getCharAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getDoubleAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getFloatAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getIntAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getLongAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.getShortAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setByteAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setCharAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setDoubleAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setFloatAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setIntAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setLongAtOffset;
|
|
|
|
import static jdk.incubator.foreign.MemoryAccess.setShortAtOffset;
|
2020-07-24 19:38:48 +02:00
|
|
|
|
2021-05-26 17:13:29 +02:00
|
|
|
class MemSegBuffer extends ResourceSupport<Buffer, MemSegBuffer> implements Buffer, ReadableComponent,
|
|
|
|
WritableComponent, BufferIntegratable {
|
2020-12-14 14:07:11 +01:00
|
|
|
private static final MemorySegment CLOSED_SEGMENT;
|
2021-05-27 17:06:30 +02:00
|
|
|
private static final MemorySegment ZERO_OFFHEAP_SEGMENT;
|
|
|
|
private static final MemorySegment ZERO_ONHEAP_SEGMENT;
|
2021-02-12 18:22:07 +01:00
|
|
|
static final Drop<MemSegBuffer> SEGMENT_CLOSE;
|
2020-12-14 14:07:11 +01:00
|
|
|
|
|
|
|
static {
|
2021-04-07 14:28:05 +02:00
|
|
|
try (ResourceScope scope = ResourceScope.newSharedScope()) {
|
2021-04-07 16:19:35 +02:00
|
|
|
// We are not allowed to allocate a zero-sized native buffer, but we *can* take a zero-sized slice from it.
|
|
|
|
// We need the CLOSED_SEGMENT to have a size of zero, because we'll use its size for bounds checks after
|
|
|
|
// the buffer is closed.
|
|
|
|
MemorySegment segment = MemorySegment.allocateNative(1, scope);
|
|
|
|
CLOSED_SEGMENT = segment.asSlice(0, 0);
|
2021-04-07 14:28:05 +02:00
|
|
|
}
|
2021-05-27 17:06:30 +02:00
|
|
|
ZERO_OFFHEAP_SEGMENT = MemorySegment.allocateNative(1, ResourceScope.newImplicitScope()).asSlice(0, 0);
|
|
|
|
ZERO_ONHEAP_SEGMENT = MemorySegment.ofArray(new byte[0]);
|
2021-03-16 17:20:12 +01:00
|
|
|
SEGMENT_CLOSE = new Drop<MemSegBuffer>() {
|
|
|
|
@Override
|
|
|
|
public void drop(MemSegBuffer buf) {
|
2021-04-07 16:19:35 +02:00
|
|
|
ResourceScope scope = buf.base.scope();
|
|
|
|
if (!scope.isImplicit()) {
|
|
|
|
scope.close();
|
|
|
|
}
|
2021-03-16 17:20:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "SEGMENT_CLOSE";
|
|
|
|
}
|
2020-12-14 14:07:11 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-05-03 15:00:49 +02:00
|
|
|
private final AllocatorControl control;
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
private MemorySegment base;
|
2020-11-16 18:00:32 +01:00
|
|
|
private MemorySegment seg;
|
2021-01-05 16:53:21 +01:00
|
|
|
private MemorySegment wseg;
|
2020-11-20 14:01:14 +01:00
|
|
|
private ByteOrder order;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
private int roff;
|
|
|
|
private int woff;
|
2021-05-03 15:00:49 +02:00
|
|
|
private boolean constBuffer;
|
2020-07-24 19:38:48 +02:00
|
|
|
|
2021-05-03 15:00:49 +02:00
|
|
|
MemSegBuffer(MemorySegment base, MemorySegment view, Drop<MemSegBuffer> drop, AllocatorControl control) {
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
super(new MakeInaccisbleOnDrop(ArcDrop.wrap(drop)));
|
2021-05-03 15:00:49 +02:00
|
|
|
this.control = control;
|
2021-03-15 16:59:42 +01:00
|
|
|
this.base = base;
|
|
|
|
seg = view;
|
|
|
|
wseg = view;
|
2020-11-20 14:01:14 +01:00
|
|
|
order = ByteOrder.nativeOrder();
|
2020-10-06 15:54:48 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 15:00:49 +02:00
|
|
|
/**
|
|
|
|
* Constructor for {@linkplain BufferAllocator#constBufferSupplier(byte[]) const buffers}.
|
|
|
|
*/
|
|
|
|
MemSegBuffer(MemSegBuffer parent) {
|
2021-05-05 12:30:52 +02:00
|
|
|
super(new MakeInaccisbleOnDrop(new ArcDrop<>(ArcDrop.acquire(parent.unsafeGetDrop()))));
|
2021-05-03 15:00:49 +02:00
|
|
|
control = parent.control;
|
|
|
|
base = parent.base;
|
|
|
|
seg = parent.seg;
|
|
|
|
wseg = parent.wseg;
|
|
|
|
order = parent.order;
|
|
|
|
roff = parent.roff;
|
|
|
|
woff = parent.woff;
|
2021-05-05 12:30:52 +02:00
|
|
|
adaptor = null;
|
2021-05-03 15:00:49 +02:00
|
|
|
constBuffer = true;
|
|
|
|
}
|
|
|
|
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
private static final class MakeInaccisbleOnDrop implements Drop<MemSegBuffer> {
|
|
|
|
final Drop<MemSegBuffer> delegate;
|
|
|
|
|
|
|
|
private MakeInaccisbleOnDrop(Drop<MemSegBuffer> delegate) {
|
|
|
|
this.delegate = delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void drop(MemSegBuffer buf) {
|
|
|
|
try {
|
|
|
|
delegate.drop(buf);
|
|
|
|
} finally {
|
|
|
|
buf.makeInaccessible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attach(MemSegBuffer buf) {
|
|
|
|
delegate.attach(buf);
|
|
|
|
}
|
2021-03-16 17:20:12 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "MemSegDrop(" + delegate + ')';
|
|
|
|
}
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Drop<MemSegBuffer> unsafeGetDrop() {
|
|
|
|
MakeInaccisbleOnDrop drop = (MakeInaccisbleOnDrop) super.unsafeGetDrop();
|
|
|
|
return drop.delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void unsafeSetDrop(Drop<MemSegBuffer> replacement) {
|
|
|
|
super.unsafeSetDrop(new MakeInaccisbleOnDrop(replacement));
|
|
|
|
}
|
|
|
|
|
2020-11-20 12:44:09 +01:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2021-02-12 18:22:07 +01:00
|
|
|
return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + seg.byteSize() + ']';
|
2020-11-20 12:44:09 +01:00
|
|
|
}
|
|
|
|
|
2021-05-28 15:13:16 +02:00
|
|
|
@Override
|
|
|
|
protected RuntimeException createResourceClosedException() {
|
|
|
|
return bufferIsClosed(this);
|
|
|
|
}
|
|
|
|
|
2020-10-06 15:54:48 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer order(ByteOrder order) {
|
2020-11-20 14:01:14 +01:00
|
|
|
this.order = order;
|
2020-10-06 15:54:48 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteOrder order() {
|
2020-11-20 14:01:14 +01:00
|
|
|
return order;
|
2020-07-24 19:38:48 +02:00
|
|
|
}
|
|
|
|
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
|
|
|
public int capacity() {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
return (int) seg.byteSize();
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
2020-08-24 17:13:04 +02:00
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int readerOffset() {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
return roff;
|
2020-08-24 17:13:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-18 15:18:22 +01:00
|
|
|
public MemSegBuffer readerOffset(int offset) {
|
|
|
|
checkRead(offset, 0);
|
|
|
|
roff = offset;
|
2020-07-29 10:30:03 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-08-24 17:13:04 +02:00
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int writerOffset() {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
return woff;
|
2020-08-24 17:13:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-18 15:18:22 +01:00
|
|
|
public MemSegBuffer writerOffset(int offset) {
|
|
|
|
checkWrite(offset, 0);
|
|
|
|
woff = offset;
|
2020-07-29 10:30:03 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer fill(byte value) {
|
2021-03-09 16:16:38 +01:00
|
|
|
checkSet(0, capacity());
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
seg.fill(value);
|
2020-07-29 10:30:03 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2021-01-15 21:32:24 +01:00
|
|
|
// <editor-fold defaultstate="collapsed" desc="Readable/WritableComponent implementation.">
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
2021-01-15 21:32:24 +01:00
|
|
|
public boolean hasReadableArray() {
|
2021-01-11 16:10:00 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-15 21:32:24 +01:00
|
|
|
public byte[] readableArray() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
2021-01-15 15:54:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-15 21:32:24 +01:00
|
|
|
public int readableArrayOffset() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
|
2021-03-18 15:18:22 +01:00
|
|
|
@Override
|
|
|
|
public int readableArrayLength() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
|
|
|
}
|
|
|
|
|
2021-01-11 16:10:00 +01:00
|
|
|
@Override
|
2021-01-15 21:32:24 +01:00
|
|
|
public long readableNativeAddress() {
|
|
|
|
return nativeAddress();
|
2020-07-24 19:38:48 +02:00
|
|
|
}
|
|
|
|
|
2021-01-11 16:10:00 +01:00
|
|
|
@Override
|
2021-01-15 21:32:24 +01:00
|
|
|
public ByteBuffer readableBuffer() {
|
2021-01-11 16:10:00 +01:00
|
|
|
var buffer = seg.asByteBuffer();
|
2021-01-15 15:54:03 +01:00
|
|
|
buffer = buffer.asReadOnlyBuffer();
|
2021-05-11 11:35:38 +02:00
|
|
|
buffer = buffer.position(readerOffset()).limit(readerOffset() + readableBytes());
|
|
|
|
return buffer.order(order);
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
|
2021-01-15 21:32:24 +01:00
|
|
|
@Override
|
|
|
|
public boolean hasWritableArray() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte[] writableArray() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int writableArrayOffset() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
|
|
|
}
|
|
|
|
|
2021-03-18 15:18:22 +01:00
|
|
|
@Override
|
|
|
|
public int writableArrayLength() {
|
|
|
|
throw new UnsupportedOperationException("This component has no backing array.");
|
|
|
|
}
|
|
|
|
|
2021-01-15 21:32:24 +01:00
|
|
|
@Override
|
|
|
|
public long writableNativeAddress() {
|
|
|
|
return nativeAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteBuffer writableBuffer() {
|
|
|
|
var buffer = wseg.asByteBuffer();
|
2021-05-11 11:35:38 +02:00
|
|
|
buffer = buffer.position(writerOffset()).limit(writerOffset() + writableBytes());
|
2021-01-15 21:32:24 +01:00
|
|
|
return buffer.order(order);
|
|
|
|
}
|
|
|
|
// </editor-fold>
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long nativeAddress() {
|
2021-05-11 11:35:38 +02:00
|
|
|
if (seg.isNative()) {
|
2021-01-15 21:32:24 +01:00
|
|
|
return seg.address().toRawLongValue();
|
|
|
|
}
|
2021-05-11 11:35:38 +02:00
|
|
|
return 0; // This is a heap segment.
|
2021-01-15 21:32:24 +01:00
|
|
|
}
|
|
|
|
|
2021-01-05 16:53:21 +01:00
|
|
|
@Override
|
2021-05-05 12:30:52 +02:00
|
|
|
public Buffer makeReadOnly() {
|
|
|
|
wseg = CLOSED_SEGMENT;
|
2021-01-05 16:53:21 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readOnly() {
|
|
|
|
return wseg == CLOSED_SEGMENT && seg != CLOSED_SEGMENT;
|
|
|
|
}
|
|
|
|
|
2020-10-15 16:20:26 +02:00
|
|
|
@Override
|
2021-05-27 14:07:31 +02:00
|
|
|
public Buffer copy(int offset, int length) {
|
2021-05-27 17:06:30 +02:00
|
|
|
checkGet(offset, length);
|
2021-05-28 13:54:16 +02:00
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("Length cannot be negative: " + length + '.');
|
|
|
|
}
|
2021-05-27 17:06:30 +02:00
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
// Special case zero-length segments, since allocators don't support allocating empty buffers.
|
|
|
|
final MemorySegment zero;
|
|
|
|
if (nativeAddress() == 0) {
|
|
|
|
zero = ZERO_ONHEAP_SEGMENT;
|
|
|
|
} else {
|
|
|
|
zero = ZERO_OFFHEAP_SEGMENT;
|
|
|
|
}
|
|
|
|
return new MemSegBuffer(zero, zero, Statics.noOpDrop(), control);
|
|
|
|
}
|
|
|
|
|
2021-05-27 14:07:31 +02:00
|
|
|
AllocatorControl.UntetheredMemory memory = control.allocateUntethered(this, length);
|
|
|
|
MemorySegment segment = memory.memory();
|
|
|
|
Buffer copy = new MemSegBuffer(segment, segment, memory.drop(), control);
|
2021-05-27 17:06:30 +02:00
|
|
|
copyInto(offset, copy, 0, length);
|
2021-05-27 14:07:31 +02:00
|
|
|
copy.writerOffset(length).order(order());
|
2021-05-05 12:30:52 +02:00
|
|
|
if (readOnly()) {
|
2021-05-27 14:07:31 +02:00
|
|
|
copy = copy.makeReadOnly();
|
2021-05-05 12:30:52 +02:00
|
|
|
}
|
2021-05-27 14:07:31 +02:00
|
|
|
return copy;
|
2020-10-15 16:20:26 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 14:39:50 +01:00
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
|
2021-04-07 14:28:05 +02:00
|
|
|
copyInto(srcPos, MemorySegment.ofArray(dest), destPos, length);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
|
2021-04-07 14:28:05 +02:00
|
|
|
copyInto(srcPos, MemorySegment.ofByteBuffer(dest.duplicate().clear()), destPos, length);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
|
2020-11-06 13:39:21 +01:00
|
|
|
private void copyInto(int srcPos, MemorySegment dest, int destPos, int length) {
|
2021-01-05 16:53:21 +01:00
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsClosed(this);
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
|
|
|
if (srcPos < 0) {
|
|
|
|
throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (seg.byteSize() < srcPos + length) {
|
|
|
|
throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " +
|
|
|
|
"srcPos = " + srcPos + ", length = " + length + '.');
|
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
dest.asSlice(destPos, length).copyFrom(seg.asSlice(srcPos, length));
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:39:50 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
|
|
|
|
if (dest instanceof MemSegBuffer) {
|
|
|
|
var memSegBuf = (MemSegBuffer) dest;
|
2021-03-09 16:16:38 +01:00
|
|
|
memSegBuf.checkSet(destPos, length);
|
2021-01-05 16:53:21 +01:00
|
|
|
copyInto(srcPos, memSegBuf.seg, destPos, length);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-18 15:18:22 +01:00
|
|
|
Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
|
2021-02-26 16:24:23 +01:00
|
|
|
@Override
|
|
|
|
public ByteCursor openCursor() {
|
|
|
|
return openCursor(readerOffset(), readableBytes());
|
|
|
|
}
|
|
|
|
|
2020-11-05 15:15:34 +01:00
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public ByteCursor openCursor(int fromOffset, int length) {
|
2020-12-14 14:07:11 +01:00
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsClosed(this);
|
2020-12-14 14:07:11 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
if (fromOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (seg.byteSize() < fromOffset + length) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " +
|
|
|
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return new ByteCursor() {
|
2020-11-05 15:15:34 +01:00
|
|
|
final MemorySegment segment = seg;
|
|
|
|
int index = fromOffset;
|
|
|
|
final int end = index + length;
|
2020-12-02 14:29:40 +01:00
|
|
|
long longValue = -1;
|
|
|
|
byte byteValue = -1;
|
2020-11-05 15:15:34 +01:00
|
|
|
|
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public boolean readLong() {
|
2020-12-02 14:29:40 +01:00
|
|
|
if (index + Long.BYTES <= end) {
|
|
|
|
longValue = getLongAtOffset(segment, index, ByteOrder.BIG_ENDIAN);
|
|
|
|
index += Long.BYTES;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-02 14:29:40 +01:00
|
|
|
public long getLong() {
|
|
|
|
return longValue;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public boolean readByte() {
|
2020-12-02 14:29:40 +01:00
|
|
|
if (index < end) {
|
|
|
|
byteValue = getByteAtOffset(segment, index);
|
|
|
|
index++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-02 14:29:40 +01:00
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
|
|
|
return end - index;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-26 16:24:23 +01:00
|
|
|
@Override
|
|
|
|
public ByteCursor openReverseCursor() {
|
|
|
|
int woff = writerOffset();
|
|
|
|
return openReverseCursor(woff == 0? 0 : woff - 1, readableBytes());
|
|
|
|
}
|
|
|
|
|
2020-11-06 13:39:21 +01:00
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public ByteCursor openReverseCursor(int fromOffset, int length) {
|
2020-12-14 14:07:11 +01:00
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsClosed(this);
|
2020-12-14 14:07:11 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
if (fromOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (seg.byteSize() <= fromOffset) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (fromOffset - length < -1) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " +
|
|
|
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return new ByteCursor() {
|
2020-11-06 13:39:21 +01:00
|
|
|
final MemorySegment segment = seg;
|
|
|
|
int index = fromOffset;
|
|
|
|
final int end = index - length;
|
2020-12-02 14:29:40 +01:00
|
|
|
long longValue = -1;
|
|
|
|
byte byteValue = -1;
|
2020-11-06 13:39:21 +01:00
|
|
|
|
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public boolean readLong() {
|
2020-12-02 14:29:40 +01:00
|
|
|
if (index - Long.BYTES >= end) {
|
|
|
|
index -= 7;
|
|
|
|
longValue = getLongAtOffset(segment, index, ByteOrder.LITTLE_ENDIAN);
|
|
|
|
index--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-02 14:29:40 +01:00
|
|
|
public long getLong() {
|
|
|
|
return longValue;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public boolean readByte() {
|
2020-12-02 14:29:40 +01:00
|
|
|
if (index > end) {
|
|
|
|
byteValue = getByteAtOffset(segment, index);
|
|
|
|
index--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-12-02 14:29:40 +01:00
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
|
|
|
return index - end;
|
|
|
|
}
|
|
|
|
};
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
|
2020-11-16 18:00:32 +01:00
|
|
|
@Override
|
2021-04-22 16:57:31 +02:00
|
|
|
public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
|
2020-11-16 18:00:32 +01:00
|
|
|
if (!isOwned()) {
|
2021-03-05 16:32:10 +01:00
|
|
|
throw attachTrace(new IllegalStateException(
|
|
|
|
"Buffer is not owned. Only owned buffers can call ensureWritable."));
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
|
|
|
if (size < 0) {
|
|
|
|
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
|
|
|
}
|
2021-04-22 16:57:31 +02:00
|
|
|
if (minimumGrowth < 0) {
|
|
|
|
throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
|
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (seg != wseg) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsReadOnly(this);
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
2020-12-16 16:44:20 +01:00
|
|
|
if (writableBytes() >= size) {
|
|
|
|
// We already have enough space.
|
|
|
|
return;
|
|
|
|
}
|
2020-12-08 19:25:53 +01:00
|
|
|
|
2020-12-16 16:44:20 +01:00
|
|
|
if (allowCompaction && writableBytes() + readerOffset() >= size) {
|
|
|
|
// We can solve this with compaction.
|
|
|
|
compact();
|
|
|
|
return;
|
2020-12-08 19:25:53 +01:00
|
|
|
}
|
2020-12-16 16:44:20 +01:00
|
|
|
|
|
|
|
// Allocate a bigger buffer.
|
2021-04-22 16:57:31 +02:00
|
|
|
long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
|
2021-02-12 18:22:07 +01:00
|
|
|
BufferAllocator.checkSize(newSize);
|
2021-05-17 15:15:19 +02:00
|
|
|
var untethered = control.allocateUntethered(this, (int) newSize);
|
|
|
|
MemorySegment newSegment = untethered.memory();
|
2020-12-16 16:44:20 +01:00
|
|
|
|
|
|
|
// Copy contents.
|
|
|
|
newSegment.copyFrom(seg);
|
|
|
|
|
2021-05-03 15:00:49 +02:00
|
|
|
// Release the old memory segment and install the new one:
|
2021-05-17 15:15:19 +02:00
|
|
|
Drop<MemSegBuffer> drop = untethered.drop();
|
|
|
|
disconnectDrop(drop);
|
2021-05-03 15:00:49 +02:00
|
|
|
attachNewMemorySegment(newSegment, drop);
|
|
|
|
}
|
|
|
|
|
2021-05-17 15:15:19 +02:00
|
|
|
private void disconnectDrop(Drop<MemSegBuffer> newDrop) {
|
2020-12-16 16:44:20 +01:00
|
|
|
var drop = unsafeGetDrop();
|
2021-05-17 15:15:19 +02:00
|
|
|
// Disconnect from the current arc drop, since we'll get our own fresh memory segment.
|
|
|
|
int roff = this.roff;
|
|
|
|
int woff = this.woff;
|
|
|
|
drop.drop(this);
|
|
|
|
unsafeSetDrop(new ArcDrop<>(newDrop));
|
|
|
|
this.roff = roff;
|
|
|
|
this.woff = woff;
|
2021-05-03 15:00:49 +02:00
|
|
|
}
|
2020-12-16 16:44:20 +01:00
|
|
|
|
2021-05-03 15:00:49 +02:00
|
|
|
private void attachNewMemorySegment(MemorySegment newSegment, Drop<MemSegBuffer> drop) {
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
base = newSegment;
|
2020-12-16 16:44:20 +01:00
|
|
|
seg = newSegment;
|
2021-01-05 16:53:21 +01:00
|
|
|
wseg = newSegment;
|
2021-05-03 15:00:49 +02:00
|
|
|
constBuffer = false;
|
2020-12-16 16:44:20 +01:00
|
|
|
drop.attach(this);
|
2020-12-08 19:25:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-04-29 15:34:04 +02:00
|
|
|
public Buffer split(int splitOffset) {
|
2021-04-22 16:57:31 +02:00
|
|
|
if (splitOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
|
|
|
|
}
|
|
|
|
if (capacity() < splitOffset) {
|
|
|
|
throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
|
|
|
|
"but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
|
|
|
|
}
|
2021-06-01 10:28:42 +02:00
|
|
|
if (!isAccessible()) {
|
|
|
|
throw attachTrace(bufferIsClosed(this));
|
|
|
|
}
|
2020-12-08 19:25:53 +01:00
|
|
|
if (!isOwned()) {
|
2021-04-29 15:34:04 +02:00
|
|
|
throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned."));
|
2020-12-08 19:25:53 +01:00
|
|
|
}
|
2021-03-18 15:18:22 +01:00
|
|
|
var drop = (ArcDrop<MemSegBuffer>) unsafeGetDrop();
|
|
|
|
unsafeSetDrop(new ArcDrop<>(drop));
|
2021-04-29 15:34:04 +02:00
|
|
|
var splitSegment = seg.asSlice(0, splitOffset);
|
2021-05-03 15:00:49 +02:00
|
|
|
var splitBuffer = new MemSegBuffer(base, splitSegment, new ArcDrop<>(drop.increment()), control);
|
2021-04-29 15:34:04 +02:00
|
|
|
splitBuffer.woff = Math.min(woff, splitOffset);
|
|
|
|
splitBuffer.roff = Math.min(roff, splitOffset);
|
|
|
|
splitBuffer.order(order);
|
2021-01-05 16:53:21 +01:00
|
|
|
boolean readOnly = readOnly();
|
2021-05-05 12:30:52 +02:00
|
|
|
if (readOnly) {
|
|
|
|
splitBuffer.makeReadOnly();
|
|
|
|
}
|
2021-05-27 17:06:30 +02:00
|
|
|
// Split preserves const-state.
|
2021-05-03 15:00:49 +02:00
|
|
|
splitBuffer.constBuffer = constBuffer;
|
2021-04-22 16:57:31 +02:00
|
|
|
seg = seg.asSlice(splitOffset, seg.byteSize() - splitOffset);
|
2021-01-05 16:53:21 +01:00
|
|
|
if (!readOnly) {
|
|
|
|
wseg = seg;
|
|
|
|
}
|
2021-04-22 16:57:31 +02:00
|
|
|
woff = Math.max(woff, splitOffset) - splitOffset;
|
|
|
|
roff = Math.max(roff, splitOffset) - splitOffset;
|
2021-04-29 15:34:04 +02:00
|
|
|
return splitBuffer;
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
|
|
|
|
2020-12-14 17:01:39 +01:00
|
|
|
@Override
|
|
|
|
public void compact() {
|
|
|
|
if (!isOwned()) {
|
2021-03-06 11:14:00 +01:00
|
|
|
throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact."));
|
2020-12-14 17:01:39 +01:00
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (readOnly()) {
|
|
|
|
throw new IllegalStateException("Buffer must be writable in order to compact, but was read-only.");
|
|
|
|
}
|
2020-12-14 17:01:39 +01:00
|
|
|
int distance = roff;
|
|
|
|
if (distance == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2020-12-16 16:03:36 +01:00
|
|
|
seg.copyFrom(seg.asSlice(roff, woff - roff));
|
2020-12-14 17:01:39 +01:00
|
|
|
roff -= distance;
|
|
|
|
woff -= distance;
|
|
|
|
}
|
|
|
|
|
2021-01-11 16:10:00 +01:00
|
|
|
@Override
|
2021-01-15 15:54:03 +01:00
|
|
|
public int countComponents() {
|
2021-01-11 16:10:00 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-15 15:54:03 +01:00
|
|
|
public int countReadableComponents() {
|
|
|
|
return readableBytes() > 0? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countWritableComponents() {
|
|
|
|
return writableBytes() > 0? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-25 12:24:52 +01:00
|
|
|
public <E extends Exception> int forEachReadable(int initialIndex, ReadableComponentProcessor<E> processor)
|
|
|
|
throws E {
|
2021-01-11 16:10:00 +01:00
|
|
|
checkRead(readerOffset(), Math.max(1, readableBytes()));
|
2021-01-15 15:54:03 +01:00
|
|
|
return processor.process(initialIndex, this)? 1 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-25 12:24:52 +01:00
|
|
|
public <E extends Exception> int forEachWritable(int initialIndex, WritableComponentProcessor<E> processor)
|
|
|
|
throws E {
|
2021-01-15 15:54:03 +01:00
|
|
|
checkWrite(writerOffset(), Math.max(1, writableBytes()));
|
2021-01-15 21:32:24 +01:00
|
|
|
return processor.process(initialIndex, this)? 1 : -1;
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 23:00:08 +01:00
|
|
|
// <editor-fold defaultstate="collapsed" desc="Primitive accessors implementation.">
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
|
|
|
public byte readByte() {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
checkRead(roff, Byte.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
byte value = getByteAtOffset(seg, roff);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Byte.BYTES;
|
2020-08-28 12:17:41 +02:00
|
|
|
return value;
|
2020-07-24 19:38:48 +02:00
|
|
|
}
|
|
|
|
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public byte getByte(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Byte.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getByteAtOffset(seg, roff);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedByte() {
|
|
|
|
checkRead(roff, Byte.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
int value = getByteAtOffset(seg, roff) & 0xFF;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Byte.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedByte(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Byte.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getByteAtOffset(seg, roff) & 0xFF;
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeByte(byte value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Byte.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setByte(int woff, byte value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedByte(int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Byte.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedByte(int woff, int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char readChar() {
|
|
|
|
checkRead(roff, 2);
|
2020-11-20 14:01:14 +01:00
|
|
|
char value = getCharAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += 2;
|
2020-08-28 12:17:41 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public char getChar(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, 2);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getCharAtOffset(seg, roff, order);
|
2020-07-24 19:38:48 +02:00
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeChar(char value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setCharAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += 2;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setChar(int woff, char value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setCharAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public short readShort() {
|
|
|
|
checkRead(roff, Short.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
short value = getShortAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Short.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public short getShort(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Short.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getShortAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedShort() {
|
|
|
|
checkRead(roff, Short.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
int value = getShortAtOffset(seg, roff, order) & 0xFFFF;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Short.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedShort(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Short.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getShortAtOffset(seg, roff, order) & 0xFFFF;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeShort(short value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setShortAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Short.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setShort(int woff, short value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setShortAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedShort(int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setShortAtOffset(wseg, woff, order, (short) (value & 0xFFFF));
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Short.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedShort(int woff, int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setShortAtOffset(wseg, woff, order, (short) (value & 0xFFFF));
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readMedium() {
|
|
|
|
checkRead(roff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
int value = order == ByteOrder.BIG_ENDIAN?
|
|
|
|
getByteAtOffset(seg, roff) << 16 |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) & 0xFF :
|
|
|
|
getByteAtOffset(seg, roff) & 0xFF |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) << 16;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += 3;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getMedium(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
return order == ByteOrder.BIG_ENDIAN?
|
|
|
|
getByteAtOffset(seg, roff) << 16 |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) & 0xFF :
|
|
|
|
getByteAtOffset(seg, roff) & 0xFF |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) << 16;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
2020-10-06 16:30:49 +02:00
|
|
|
@Override
|
|
|
|
public int readUnsignedMedium() {
|
|
|
|
checkRead(roff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
int value = order == ByteOrder.BIG_ENDIAN?
|
|
|
|
(getByteAtOffset(seg, roff) << 16 |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) & 0xFF) & 0xFFFFFF :
|
|
|
|
(getByteAtOffset(seg, roff) & 0xFF |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) << 16) & 0xFFFFFF;
|
2020-10-06 16:30:49 +02:00
|
|
|
roff += 3;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedMedium(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
return order == ByteOrder.BIG_ENDIAN?
|
|
|
|
(getByteAtOffset(seg, roff) << 16 |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) & 0xFF) & 0xFFFFFF :
|
|
|
|
(getByteAtOffset(seg, roff) & 0xFF |
|
|
|
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
|
|
|
getByteAtOffset(seg, roff + 2) << 16) & 0xFFFFFF;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeMedium(int value) {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
checkWrite(woff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
if (order == ByteOrder.BIG_ENDIAN) {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
} else {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
woff += 3;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setMedium(int woff, int value) {
|
2021-03-09 16:16:38 +01:00
|
|
|
checkSet(woff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
if (order == ByteOrder.BIG_ENDIAN) {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
} else {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-10-06 16:30:49 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedMedium(int value) {
|
2020-10-06 16:30:49 +02:00
|
|
|
checkWrite(woff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
if (order == ByteOrder.BIG_ENDIAN) {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
} else {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
}
|
|
|
|
woff += 3;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedMedium(int woff, int value) {
|
2021-03-09 16:16:38 +01:00
|
|
|
checkSet(woff, 3);
|
2020-11-20 14:01:14 +01:00
|
|
|
if (order == ByteOrder.BIG_ENDIAN) {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
} else {
|
2021-01-05 16:53:21 +01:00
|
|
|
setByteAtOffset(wseg, woff, (byte) (value & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
setByteAtOffset(wseg, woff + 2, (byte) (value >> 16 & 0xFF));
|
2020-10-06 16:30:49 +02:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
|
|
|
public int readInt() {
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
checkRead(roff, Integer.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
int value = getIntAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Integer.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getInt(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Integer.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getIntAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readUnsignedInt() {
|
|
|
|
checkRead(roff, Integer.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
long value = getIntAtOffset(seg, roff, order) & 0xFFFFFFFFL;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Integer.BYTES;
|
2020-08-28 12:17:41 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getUnsignedInt(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Integer.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getIntAtOffset(seg, roff, order) & 0xFFFFFFFFL;
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
2020-08-28 12:17:41 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeInt(int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setIntAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Integer.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setInt(int woff, int value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setIntAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedInt(long value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setIntAtOffset(wseg, woff, order, (int) (value & 0xFFFFFFFFL));
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Integer.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedInt(int woff, long value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setIntAtOffset(wseg, woff, order, (int) (value & 0xFFFFFFFFL));
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float readFloat() {
|
|
|
|
checkRead(roff, Float.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
float value = getFloatAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Float.BYTES;
|
2020-08-28 12:17:41 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public float getFloat(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Float.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getFloatAtOffset(seg, roff, order);
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeFloat(float value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setFloatAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Float.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setFloat(int woff, float value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setFloatAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
2020-08-28 12:17:41 +02:00
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
@Override
|
|
|
|
public long readLong() {
|
|
|
|
checkRead(roff, Long.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
long value = getLongAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Long.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getLong(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Long.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getLongAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeLong(long value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setLongAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Long.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setLong(int woff, long value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setLongAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double readDouble() {
|
|
|
|
checkRead(roff, Double.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
double value = getDoubleAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
roff += Double.BYTES;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public double getDouble(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
checkGet(roff, Double.BYTES);
|
2020-11-20 14:01:14 +01:00
|
|
|
return getDoubleAtOffset(seg, roff, order);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeDouble(double value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setDoubleAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
woff += Double.BYTES;
|
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setDouble(int woff, double value) {
|
2020-12-14 14:07:11 +01:00
|
|
|
try {
|
2021-01-05 16:53:21 +01:00
|
|
|
setDoubleAtOffset(wseg, woff, order, value);
|
2020-12-14 14:07:11 +01:00
|
|
|
return this;
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
throw checkWriteState(e);
|
|
|
|
}
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
Make cleaner in pooledDirectWithCleaner return segments to pool instead of deallocating
Motivation:
Allocating memory is expensive, which is why we pool our allocations.
The cleaner, when used with pooled memory, should then return that memory to the pool instead of deallocating it.
The purpose of the cleaner is, after all, to avoid having to track the reference counts so precisely.
Modification:
The NativeMemoryCleanerDrop is now able to either recover lost memory segments, when a buffer wasn't closed explicitly
and is being cleaned by the GC, or return the buffer to the pool via ordinary drop.
The GatedCleanable has been added, because buffer ownership transfer involves generating new memory segments,
and in those cases we need to invalidate the old cleanables without deallocating the tracked memory segment or returning
it to the pool more than once.
Result:
The pooledDirectWithCleaner allocator is now able to reuse memory segments, even when their references are forgotten and
they processed by the cleaner thread.
2020-09-25 12:15:45 +02:00
|
|
|
// </editor-fold>
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
|
2020-07-24 19:38:48 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
protected Owned<MemSegBuffer> prepareSend() {
|
2020-12-14 14:07:11 +01:00
|
|
|
var order = this.order;
|
|
|
|
var roff = this.roff;
|
|
|
|
var woff = this.woff;
|
2021-01-05 16:53:21 +01:00
|
|
|
var readOnly = readOnly();
|
2021-05-03 15:00:49 +02:00
|
|
|
var isConst = constBuffer;
|
2021-04-07 14:28:05 +02:00
|
|
|
MemorySegment transferSegment = seg;
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
MemorySegment base = this.base;
|
2020-12-14 14:07:11 +01:00
|
|
|
makeInaccessible();
|
2021-02-12 18:22:07 +01:00
|
|
|
return new Owned<MemSegBuffer>() {
|
2020-07-24 19:38:48 +02:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public MemSegBuffer transferOwnership(Drop<MemSegBuffer> drop) {
|
2021-05-03 15:00:49 +02:00
|
|
|
MemSegBuffer copy = new MemSegBuffer(base, transferSegment, drop, control);
|
2020-12-14 14:07:11 +01:00
|
|
|
copy.order = order;
|
|
|
|
copy.roff = roff;
|
|
|
|
copy.woff = woff;
|
2021-05-05 12:30:52 +02:00
|
|
|
if (readOnly) {
|
|
|
|
copy.makeReadOnly();
|
|
|
|
}
|
2021-05-03 15:00:49 +02:00
|
|
|
copy.constBuffer = isConst;
|
2020-07-24 19:38:48 +02:00
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2020-08-24 17:13:04 +02:00
|
|
|
|
2020-12-14 14:07:11 +01:00
|
|
|
void makeInaccessible() {
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
base = CLOSED_SEGMENT;
|
2020-12-14 14:07:11 +01:00
|
|
|
seg = CLOSED_SEGMENT;
|
2021-01-05 16:53:21 +01:00
|
|
|
wseg = CLOSED_SEGMENT;
|
2020-12-14 14:07:11 +01:00
|
|
|
roff = 0;
|
|
|
|
woff = 0;
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:21:20 +01:00
|
|
|
@Override
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
public boolean isOwned() {
|
2021-03-18 15:18:22 +01:00
|
|
|
return super.isOwned() && ((ArcDrop<MemSegBuffer>) unsafeGetDrop()).isOwned();
|
2020-10-30 14:21:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
Allow slices to obtain ownership when parent is closed
Motivation:
It is kind of a weird internal and hidden state, that slices were special.
For instance, slices could not be sent, and they could never obtain ownership.
This means buffers from slices behaved differently from allocated buffers.
In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour.
Modification:
- The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting).
- The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like.
- Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop.
- Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state.
- SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices.
- We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice).
- CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with.
- The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point.
- MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice.
Result:
It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
|
|
|
public int countBorrows() {
|
2021-03-18 15:18:22 +01:00
|
|
|
return super.countBorrows() + ((ArcDrop<MemSegBuffer>) unsafeGetDrop()).countBorrows();
|
2020-10-30 14:21:20 +01:00
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
private void checkRead(int index, int size) {
|
|
|
|
if (index < 0 || woff < index + size) {
|
2021-01-11 16:10:00 +01:00
|
|
|
throw readAccessCheckException(index);
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-09 12:02:46 +01:00
|
|
|
private void checkGet(int index, int size) {
|
|
|
|
if (index < 0 || seg.byteSize() < index + size) {
|
|
|
|
throw readAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Generate complete and tested Buf API
Motivation:
The Buf API is wide, taking into account signedness, endian-ness, and so on, for all primitive
types.
Modification:
A code generator has been added which add API, implementation, and tests, to the Buf, BBuf,
and BBufTest files respectively.
Result:
We have a complete and fully tested accessor API in the Buf interface, which is still somewhat
easy to bulk-modify using the code generator.
2020-09-10 18:05:36 +02:00
|
|
|
private void checkWrite(int index, int size) {
|
2021-03-09 16:16:38 +01:00
|
|
|
if (index < roff || wseg.byteSize() < index + size) {
|
|
|
|
throw writeAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkSet(int index, int size) {
|
2021-01-05 16:53:21 +01:00
|
|
|
if (index < 0 || wseg.byteSize() < index + size) {
|
2021-01-11 16:10:00 +01:00
|
|
|
throw writeAccessCheckException(index);
|
2020-08-24 17:13:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 14:07:11 +01:00
|
|
|
private RuntimeException checkWriteState(IndexOutOfBoundsException ioobe) {
|
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
return bufferIsClosed(this);
|
2020-12-14 14:07:11 +01:00
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (wseg != seg) {
|
2021-05-28 15:13:16 +02:00
|
|
|
return bufferIsReadOnly(this);
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
2020-12-14 14:07:11 +01:00
|
|
|
return ioobe;
|
|
|
|
}
|
|
|
|
|
2021-01-11 16:10:00 +01:00
|
|
|
private RuntimeException readAccessCheckException(int index) {
|
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsClosed(this);
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
return outOfBounds(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
private RuntimeException writeAccessCheckException(int index) {
|
2020-12-14 14:07:11 +01:00
|
|
|
if (seg == CLOSED_SEGMENT) {
|
2021-05-28 15:13:16 +02:00
|
|
|
throw bufferIsClosed(this);
|
2020-12-14 14:07:11 +01:00
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (wseg != seg) {
|
2021-05-28 15:13:16 +02:00
|
|
|
return bufferIsReadOnly(this);
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
2021-01-11 16:10:00 +01:00
|
|
|
return outOfBounds(index);
|
2020-08-24 17:13:04 +02:00
|
|
|
}
|
2020-11-16 18:00:32 +01:00
|
|
|
|
2021-01-11 16:10:00 +01:00
|
|
|
private IndexOutOfBoundsException outOfBounds(int index) {
|
|
|
|
return new IndexOutOfBoundsException(
|
|
|
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
2021-03-09 16:16:38 +01:00
|
|
|
seg.byteSize() + "].");
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
|
2020-11-16 18:00:32 +01:00
|
|
|
Object recoverableMemory() {
|
2021-03-19 17:43:05 +01:00
|
|
|
return base;
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:54:11 +01:00
|
|
|
// <editor-fold name="BufferIntegratable methods">
|
|
|
|
private ByteBufAdaptor adaptor;
|
|
|
|
@Override
|
|
|
|
public ByteBuf asByteBuf() {
|
|
|
|
ByteBufAdaptor bba = adaptor;
|
|
|
|
if (bba == null) {
|
|
|
|
ByteBufAllocatorAdaptor alloc = new ByteBufAllocatorAdaptor(
|
|
|
|
BufferAllocator.heap(), BufferAllocator.direct());
|
|
|
|
return adaptor = new ByteBufAdaptor(alloc, this);
|
|
|
|
}
|
|
|
|
return bba;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MemSegBuffer retain(int increment) {
|
|
|
|
for (int i = 0; i < increment; i++) {
|
|
|
|
acquire();
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int refCnt() {
|
|
|
|
return isAccessible()? 1 + countBorrows() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MemSegBuffer retain() {
|
|
|
|
return retain(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MemSegBuffer touch() {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MemSegBuffer touch(Object hint) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean release() {
|
|
|
|
return release(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean release(int decrement) {
|
2021-05-31 15:06:48 +02:00
|
|
|
int refCount = 1 + countBorrows();
|
|
|
|
if (!isAccessible() || decrement > refCount) {
|
|
|
|
throw new IllegalReferenceCountException(refCount, -decrement);
|
2021-05-28 17:10:46 +02:00
|
|
|
}
|
2021-02-17 13:54:11 +01:00
|
|
|
for (int i = 0; i < decrement; i++) {
|
2021-05-31 15:06:48 +02:00
|
|
|
try {
|
|
|
|
close();
|
|
|
|
} catch (RuntimeException e) {
|
|
|
|
throw new IllegalReferenceCountException(e);
|
|
|
|
}
|
2021-02-17 13:54:11 +01:00
|
|
|
}
|
|
|
|
return !isAccessible();
|
|
|
|
}
|
|
|
|
// </editor-fold>
|
2020-11-17 15:25:26 +01:00
|
|
|
}
|