2020-10-28 14:38:14 +01: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:
|
|
|
|
*
|
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* 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:38:11 +01:00
|
|
|
package io.netty.buffer.api;
|
2020-10-28 14:38:14 +01:00
|
|
|
|
2020-10-30 14:39:50 +01:00
|
|
|
import java.nio.ByteBuffer;
|
2020-10-28 14:38:14 +01:00
|
|
|
import java.nio.ByteOrder;
|
|
|
|
import java.util.Arrays;
|
2021-01-18 16:06:53 +01:00
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.IdentityHashMap;
|
2020-12-03 17:48:28 +01:00
|
|
|
import java.util.Objects;
|
2021-01-18 16:06:53 +01:00
|
|
|
import java.util.Set;
|
|
|
|
import java.util.stream.Stream;
|
2020-10-28 14:38:14 +01:00
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implements Buffer {
|
2020-10-28 14:38:14 +01:00
|
|
|
/**
|
|
|
|
* The max array size is JVM implementation dependant, but most seem to settle on {@code Integer.MAX_VALUE - 8}.
|
|
|
|
* We set the max composite buffer capacity to the same, since it would otherwise be impossible to create a
|
|
|
|
* non-composite copy of the buffer.
|
|
|
|
*/
|
|
|
|
private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
|
2021-03-16 17:20:12 +01:00
|
|
|
private static final Drop<CompositeBuffer> COMPOSITE_DROP = new Drop<CompositeBuffer>() {
|
|
|
|
@Override
|
|
|
|
public void drop(CompositeBuffer buf) {
|
|
|
|
for (Buffer b : buf.bufs) {
|
|
|
|
b.close();
|
|
|
|
}
|
|
|
|
buf.makeInaccessible();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "COMPOSITE_DROP";
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private final BufferAllocator allocator;
|
|
|
|
private final TornBufferAccessors tornBufAccessors;
|
|
|
|
private Buffer[] bufs;
|
2020-11-16 18:00:32 +01:00
|
|
|
private int[] offsets; // The offset, for the composite buffer, where each constituent buffer starts.
|
|
|
|
private int capacity;
|
2020-10-28 14:38:14 +01:00
|
|
|
private int roff;
|
|
|
|
private int woff;
|
|
|
|
private int subOffset; // The next offset *within* a consituent buffer to read from or write to.
|
2020-12-08 19:25:53 +01:00
|
|
|
private ByteOrder order;
|
2020-12-14 14:07:11 +01:00
|
|
|
private boolean closed;
|
2021-01-05 16:53:21 +01:00
|
|
|
private boolean readOnly;
|
2020-10-28 14:38:14 +01:00
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
CompositeBuffer(BufferAllocator allocator, Deref<Buffer>[] refs) {
|
2021-03-16 17:22:41 +01:00
|
|
|
this(allocator, filterExternalBufs(refs), COMPOSITE_DROP, false);
|
2021-01-15 15:54:03 +01:00
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private static Buffer[] filterExternalBufs(Deref<Buffer>[] refs) {
|
2021-01-18 10:56:33 +01:00
|
|
|
// We filter out all zero-capacity buffers because they wouldn't contribute to the composite buffer anyway,
|
|
|
|
// and also, by ensuring that all constituent buffers contribute to the size of the composite buffer,
|
|
|
|
// we make sure that the number of composite buffers will never become greater than the number of bytes in
|
|
|
|
// the composite buffer.
|
|
|
|
// This restriction guarantees that methods like countComponents, forEachReadable and forEachWritable,
|
|
|
|
// will never overflow their component counts.
|
2021-01-15 15:54:03 +01:00
|
|
|
// Allocating a new array unconditionally also prevents external modification of the array.
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer[] bufs = Arrays.stream(refs)
|
|
|
|
.map(r -> r.get()) // Increments reference counts.
|
|
|
|
.filter(CompositeBuffer::discardEmpty)
|
|
|
|
.flatMap(CompositeBuffer::flattenBuffer)
|
|
|
|
.toArray(Buffer[]::new);
|
2021-01-18 16:06:53 +01:00
|
|
|
// Make sure there are no duplicates among the buffers.
|
2021-02-12 18:22:07 +01:00
|
|
|
Set<Buffer> duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>());
|
2021-01-18 16:06:53 +01:00
|
|
|
duplicatesCheck.addAll(Arrays.asList(bufs));
|
|
|
|
if (duplicatesCheck.size() < bufs.length) {
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
buf.close(); // Undo the increment we did with Deref.get().
|
|
|
|
}
|
2021-01-18 16:06:53 +01:00
|
|
|
throw new IllegalArgumentException(
|
|
|
|
"Cannot create composite buffer with duplicate constituent buffer components.");
|
|
|
|
}
|
|
|
|
return bufs;
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private static boolean discardEmpty(Buffer buf) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
if (buf.capacity() > 0) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
// If we filter a buffer out, then we must make sure to close it since we incremented the reference count
|
|
|
|
// with Deref.get() earlier.
|
|
|
|
buf.close();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private static Stream<Buffer> flattenBuffer(Buffer buf) {
|
|
|
|
if (buf instanceof CompositeBuffer) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
// Extract components and move our reference count from the composite onto the components.
|
2021-02-12 18:22:07 +01:00
|
|
|
var composite = (CompositeBuffer) buf;
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
var bufs = composite.bufs;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer b : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
b.acquire();
|
|
|
|
}
|
|
|
|
buf.close(); // Important: acquire on components *before* closing composite.
|
|
|
|
return Stream.of(bufs);
|
2021-01-18 16:06:53 +01:00
|
|
|
}
|
|
|
|
return Stream.of(buf);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 17:22:41 +01:00
|
|
|
private CompositeBuffer(BufferAllocator allocator, Buffer[] bufs, Drop<CompositeBuffer> drop,
|
2021-02-12 18:22:07 +01:00
|
|
|
boolean acquireBufs) {
|
2020-10-30 14:21:20 +01:00
|
|
|
super(drop);
|
2020-11-16 18:00:32 +01:00
|
|
|
this.allocator = allocator;
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
if (acquireBufs) {
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
buf.acquire();
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (bufs.length > 0) {
|
|
|
|
ByteOrder targetOrder = bufs[0].order();
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
if (buf.order() != targetOrder) {
|
|
|
|
throw new IllegalArgumentException("Constituent buffers have inconsistent byte order.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
order = bufs[0].order();
|
2021-01-05 16:53:21 +01:00
|
|
|
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
boolean targetReadOnly = bufs[0].readOnly();
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
if (buf.readOnly() != targetReadOnly) {
|
|
|
|
throw new IllegalArgumentException("Constituent buffers have inconsistent read-only state.");
|
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
readOnly = targetReadOnly;
|
|
|
|
} else {
|
|
|
|
order = ByteOrder.nativeOrder();
|
2021-01-05 16:53:21 +01:00
|
|
|
}
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
this.bufs = bufs;
|
|
|
|
computeBufferOffsets();
|
2021-02-12 18:22:07 +01:00
|
|
|
tornBufAccessors = new TornBufferAccessors(this);
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
// Always close bufs on exception, regardless of acquireBufs value.
|
|
|
|
// If acquireBufs is false, it just means the ref count increments happened prior to this constructor call.
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
Introduce Deref abstraction
Motivation:
Sometimes, we wish to operate on both buffers and anything that can produce a buffer.
For instance, when making a composite buffer, we could compose either buffers or sends.
Modification:
Introduce a Deref interface, which is extended by both Rc and Send.
A Deref can be used to acquire an Rc instance, and in doing so will also acquire a reference to the Rc.
That is, dereferencing increases the reference count.
For Rc itself, this just delegates to Rc.acquire, while for Send it delegates to Send.receive, and can only be called once.
The Allocator.compose method has been changed to take Derefs.
This allows us to compose either Bufs or Sends of bufs.
Or a mix.
Extra care and caution has been added to the code, to make sure the reference counts are managed correctly when composing buffers, now that it's a more complicated operation.
A handful of convenience methods for working with Sends have also been added to the Send interface.
Result:
We can now build a composite buffer out of sends of buffers.
2021-02-11 14:08:22 +01:00
|
|
|
buf.close();
|
|
|
|
}
|
|
|
|
throw e;
|
2020-12-03 17:48:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void computeBufferOffsets() {
|
|
|
|
if (bufs.length > 0) {
|
|
|
|
int woff = 0;
|
|
|
|
int roff = 0;
|
2020-10-28 14:38:14 +01:00
|
|
|
boolean woffMidpoint = false;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (buf.writableBytes() == 0) {
|
|
|
|
woff += buf.capacity();
|
|
|
|
} else if (!woffMidpoint) {
|
2020-11-11 23:00:08 +01:00
|
|
|
woff += buf.writerOffset();
|
2020-10-28 14:38:14 +01:00
|
|
|
woffMidpoint = true;
|
2020-11-11 23:00:08 +01:00
|
|
|
} else if (buf.writerOffset() != 0) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new IllegalArgumentException(
|
2020-12-03 17:48:28 +01:00
|
|
|
"The given buffers cannot be composed because they leave an unwritten gap: " +
|
2020-10-28 14:38:14 +01:00
|
|
|
Arrays.toString(bufs) + '.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boolean roffMidpoint = false;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (buf.readableBytes() == 0 && buf.writableBytes() == 0) {
|
|
|
|
roff += buf.capacity();
|
|
|
|
} else if (!roffMidpoint) {
|
2020-11-11 23:00:08 +01:00
|
|
|
roff += buf.readerOffset();
|
2020-10-28 14:38:14 +01:00
|
|
|
roffMidpoint = true;
|
2020-11-11 23:00:08 +01:00
|
|
|
} else if (buf.readerOffset() != 0) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new IllegalArgumentException(
|
2020-12-03 17:48:28 +01:00
|
|
|
"The given buffers cannot be composed because they leave an unread gap: " +
|
2020-10-28 14:38:14 +01:00
|
|
|
Arrays.toString(bufs) + '.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert roff <= woff:
|
|
|
|
"The given buffers place the read offset ahead of the write offset: " + Arrays.toString(bufs) + '.';
|
2020-12-03 17:48:28 +01:00
|
|
|
// Commit computed offsets.
|
|
|
|
this.woff = woff;
|
|
|
|
this.roff = roff;
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
2020-11-16 18:00:32 +01:00
|
|
|
|
2020-10-28 14:38:14 +01:00
|
|
|
offsets = new int[bufs.length];
|
|
|
|
long cap = 0;
|
|
|
|
for (int i = 0; i < bufs.length; i++) {
|
|
|
|
offsets[i] = (int) cap;
|
|
|
|
cap += bufs[i].capacity();
|
|
|
|
}
|
|
|
|
if (cap > MAX_CAPACITY) {
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
"Combined size of the constituent buffers is too big. " +
|
|
|
|
"The maximum buffer capacity is " + MAX_CAPACITY + " (Interger.MAX_VALUE - 8), " +
|
|
|
|
"but the sum of the constituent buffer capacities was " + cap + '.');
|
|
|
|
}
|
|
|
|
capacity = (int) cap;
|
|
|
|
}
|
|
|
|
|
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:" + capacity + ']';
|
2020-11-20 12:44:09 +01:00
|
|
|
}
|
|
|
|
|
2020-10-28 14:38:14 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer order(ByteOrder order) {
|
2020-12-10 12:51:18 +01:00
|
|
|
if (this.order != order) {
|
|
|
|
this.order = order;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-12-10 12:51:18 +01:00
|
|
|
buf.order(order);
|
|
|
|
}
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteOrder order() {
|
2020-12-08 19:25:53 +01:00
|
|
|
return order;
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int capacity() {
|
|
|
|
return capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int readerOffset() {
|
2020-10-28 14:38:14 +01:00
|
|
|
return roff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer readerOffset(int index) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepRead(index, 0);
|
|
|
|
int indexLeft = index;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-11-11 23:00:08 +01:00
|
|
|
buf.readerOffset(Math.min(indexLeft, buf.capacity()));
|
2020-10-28 14:38:14 +01:00
|
|
|
indexLeft = Math.max(0, indexLeft - buf.capacity());
|
|
|
|
}
|
|
|
|
roff = index;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int writerOffset() {
|
2020-10-28 14:38:14 +01:00
|
|
|
return woff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writerOffset(int index) {
|
2020-10-28 14:38:14 +01:00
|
|
|
checkWriteBounds(index, 0);
|
|
|
|
int indexLeft = index;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-11-11 23:00:08 +01:00
|
|
|
buf.writerOffset(Math.min(indexLeft, buf.capacity()));
|
2020-10-28 14:38:14 +01:00
|
|
|
indexLeft = Math.max(0, indexLeft - buf.capacity());
|
|
|
|
}
|
|
|
|
woff = index;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer fill(byte value) {
|
|
|
|
for (Buffer buf : bufs) {
|
2020-10-28 14:38:14 +01:00
|
|
|
buf.fill(value);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-11 16:10:00 +01:00
|
|
|
public long nativeAddress() {
|
2020-10-28 14:38:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-05 16:53:21 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer readOnly(boolean readOnly) {
|
|
|
|
for (Buffer buf : bufs) {
|
2021-01-05 16:53:21 +01:00
|
|
|
buf.readOnly(readOnly);
|
|
|
|
}
|
|
|
|
this.readOnly = readOnly;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readOnly() {
|
|
|
|
return readOnly;
|
|
|
|
}
|
|
|
|
|
2020-10-28 14:38:14 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer slice(int offset, int length) {
|
2020-10-28 14:38:14 +01:00
|
|
|
checkWriteBounds(offset, length);
|
|
|
|
if (offset < 0 || length < 0) {
|
2020-11-12 14:55:42 +01:00
|
|
|
throw new IllegalArgumentException(
|
2020-10-28 14:38:14 +01:00
|
|
|
"Offset and length cannot be negative, but offset was " +
|
|
|
|
offset + ", and length was " + length + '.');
|
|
|
|
}
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer choice = (Buffer) chooseBuffer(offset, 0);
|
2021-03-16 17:22:41 +01:00
|
|
|
Buffer[] slices;
|
|
|
|
|
|
|
|
if (length > 0) {
|
|
|
|
slices = new Buffer[bufs.length];
|
|
|
|
int off = subOffset;
|
|
|
|
int cap = length;
|
|
|
|
int i;
|
|
|
|
for (i = searchOffsets(offset); cap > 0; i++) {
|
|
|
|
var buf = bufs[i];
|
|
|
|
int avail = buf.capacity() - off;
|
|
|
|
slices[i] = buf.slice(off, Math.min(cap, avail));
|
|
|
|
cap -= avail;
|
|
|
|
off = 0;
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
2021-03-16 17:22:41 +01:00
|
|
|
slices = Arrays.copyOf(slices, i);
|
|
|
|
} else {
|
|
|
|
// Specialize for length == 0, since we must slice from at least one constituent buffer.
|
|
|
|
slices = new Buffer[] { choice.slice(subOffset, 0) };
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
2021-03-16 17:22:41 +01:00
|
|
|
|
|
|
|
// Use the constructor that skips filtering out empty buffers, and skips acquiring on the buffers.
|
|
|
|
// This is important because 1) slice() already acquired the buffers, and 2) if this slice is empty
|
|
|
|
// then we need to keep holding on to it to prevent this originating composite buffer from getting
|
|
|
|
// ownership. If it did, its behaviour would be inconsistent with that of a non-composite buffer.
|
|
|
|
return new CompositeBuffer(allocator, slices, COMPOSITE_DROP, false);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2020-10-30 14:39:50 +01:00
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
|
|
|
|
copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
|
|
|
|
copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length);
|
|
|
|
}
|
|
|
|
|
2020-11-06 13:39:21 +01:00
|
|
|
private void copyInto(int srcPos, CopyInto dest, int destPos, int length) {
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (srcPos < 0) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(srcPos, false);
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
if (srcPos + length > capacity) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(srcPos + length, false);
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
while (length > 0) {
|
2021-02-12 18:22:07 +01:00
|
|
|
var buf = (Buffer) chooseBuffer(srcPos, 0);
|
2020-11-12 14:55:42 +01:00
|
|
|
int toCopy = Math.min(buf.capacity() - subOffset, length);
|
2020-11-06 13:39:21 +01:00
|
|
|
dest.copyInto(buf, subOffset, destPos, toCopy);
|
|
|
|
srcPos += toCopy;
|
|
|
|
destPos += toCopy;
|
|
|
|
length -= toCopy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@FunctionalInterface
|
|
|
|
private interface CopyInto {
|
2021-02-12 18:22:07 +01:00
|
|
|
void copyInto(Buffer src, int srcPos, int destPos, int length);
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
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) {
|
2020-10-30 14:39:50 +01:00
|
|
|
if (length < 0) {
|
|
|
|
throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (srcPos < 0) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(srcPos, false);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
if (srcPos + length > capacity) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(srcPos + length, false);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
|
|
|
|
// Iterate in reverse to account for src and dest buffer overlap.
|
|
|
|
// todo optimise by delegating to constituent buffers.
|
2020-12-07 14:56:03 +01:00
|
|
|
var cursor = openReverseCursor(srcPos + length - 1, length);
|
2020-11-06 13:39:21 +01:00
|
|
|
ByteOrder prevOrder = dest.order();
|
|
|
|
// We read longs in BE, in reverse, so they need to be flipped for writing.
|
|
|
|
dest.order(ByteOrder.LITTLE_ENDIAN);
|
|
|
|
try {
|
2020-12-07 14:56:03 +01:00
|
|
|
while (cursor.readLong()) {
|
2020-11-06 13:39:21 +01:00
|
|
|
length -= Long.BYTES;
|
2020-12-02 14:29:40 +01:00
|
|
|
dest.setLong(destPos + length, cursor.getLong());
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
2020-12-07 14:56:03 +01:00
|
|
|
while (cursor.readByte()) {
|
2020-12-02 14:29:40 +01:00
|
|
|
dest.setByte(destPos + --length, cursor.getByte());
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
dest.order(prevOrder);
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 15:18:22 +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-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 (capacity < fromOffset + length) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset+length is beyond the end of the buffer: " +
|
|
|
|
"fromOffset=" + fromOffset + ", length=" + length + '.');
|
|
|
|
}
|
2020-11-05 15:15:34 +01:00
|
|
|
int startBufferIndex = searchOffsets(fromOffset);
|
|
|
|
int off = fromOffset - offsets[startBufferIndex];
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer startBuf = bufs[startBufferIndex];
|
2020-12-07 14:56:03 +01:00
|
|
|
ByteCursor startCursor = startBuf.openCursor(off, Math.min(startBuf.capacity() - off, length));
|
2020-12-02 14:29:40 +01:00
|
|
|
return new ByteCursor() {
|
2020-11-05 15:15:34 +01:00
|
|
|
int index = fromOffset;
|
|
|
|
final int end = fromOffset + length;
|
|
|
|
int bufferIndex = startBufferIndex;
|
2020-12-07 16:00:45 +01:00
|
|
|
int initOffset = startCursor.currentOffset();
|
2020-12-02 14:29:40 +01:00
|
|
|
ByteCursor cursor = startCursor;
|
|
|
|
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-07 16:00:45 +01:00
|
|
|
if (cursor.readLong()) {
|
|
|
|
longValue = cursor.getLong();
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
if (bytesLeft() >= Long.BYTES) {
|
2020-12-07 16:00:45 +01:00
|
|
|
longValue = nextLongFromBytes();
|
2020-12-02 14:29:40 +01:00
|
|
|
return true;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return false;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private long nextLongFromBytes() {
|
2020-12-07 16:00:45 +01:00
|
|
|
if (cursor.bytesLeft() == 0) {
|
|
|
|
nextCursor();
|
|
|
|
if (cursor.readLong()) {
|
|
|
|
return cursor.getLong();
|
|
|
|
}
|
|
|
|
}
|
2020-11-05 15:15:34 +01:00
|
|
|
long val = 0;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2020-12-07 14:56:03 +01:00
|
|
|
readByte();
|
2020-11-05 15:15:34 +01:00
|
|
|
val <<= 8;
|
2020-12-02 14:29:40 +01:00
|
|
|
val |= getByte();
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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-07 16:00:45 +01:00
|
|
|
if (cursor.readByte()) {
|
|
|
|
byteValue = cursor.getByte();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (bytesLeft() > 0) {
|
|
|
|
nextCursor();
|
|
|
|
cursor.readByte();
|
2020-12-02 14:29:40 +01:00
|
|
|
byteValue = cursor.getByte();
|
|
|
|
return true;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-07 16:00:45 +01:00
|
|
|
private void nextCursor() {
|
|
|
|
bufferIndex++;
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer nextBuf = bufs[bufferIndex];
|
2020-12-07 16:00:45 +01:00
|
|
|
cursor = nextBuf.openCursor(0, Math.min(nextBuf.capacity(), bytesLeft()));
|
|
|
|
initOffset = 0;
|
|
|
|
}
|
|
|
|
|
2020-12-02 14:29:40 +01:00
|
|
|
@Override
|
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
2020-12-07 16:00:45 +01:00
|
|
|
int currOff = cursor.currentOffset();
|
|
|
|
index += currOff - initOffset;
|
|
|
|
initOffset = currOff;
|
2020-11-05 15:15:34 +01:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
2020-12-07 16:00:45 +01:00
|
|
|
return end - currentOffset();
|
2020-11-05 15:15:34 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
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-11-06 13:39:21 +01:00
|
|
|
if (fromOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
if (fromOffset - length < -1) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset-length would underflow the buffer: " +
|
|
|
|
"fromOffset=" + fromOffset + ", length=" + length + '.');
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
int startBufferIndex = searchOffsets(fromOffset);
|
|
|
|
int off = fromOffset - offsets[startBufferIndex];
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer startBuf = bufs[startBufferIndex];
|
2020-12-07 14:56:03 +01:00
|
|
|
ByteCursor startCursor = startBuf.openReverseCursor(off, Math.min(off + 1, length));
|
2020-12-02 14:29:40 +01:00
|
|
|
return new ByteCursor() {
|
2020-11-06 13:39:21 +01:00
|
|
|
int index = fromOffset;
|
|
|
|
final int end = fromOffset - length;
|
|
|
|
int bufferIndex = startBufferIndex;
|
2020-12-07 16:00:45 +01:00
|
|
|
int initOffset = startCursor.currentOffset();
|
2020-12-02 14:29:40 +01:00
|
|
|
ByteCursor cursor = startCursor;
|
|
|
|
long longValue = -1;
|
|
|
|
byte byteValue = -1;
|
2020-10-30 14:39:50 +01:00
|
|
|
|
2020-11-06 13:39:21 +01:00
|
|
|
@Override
|
2020-12-07 14:56:03 +01:00
|
|
|
public boolean readLong() {
|
2020-12-07 16:00:45 +01:00
|
|
|
if (cursor.readLong()) {
|
|
|
|
longValue = cursor.getLong();
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
if (bytesLeft() >= Long.BYTES) {
|
2020-12-07 16:00:45 +01:00
|
|
|
longValue = nextLongFromBytes();
|
2020-12-02 14:29:40 +01:00
|
|
|
return true;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return false;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private long nextLongFromBytes() {
|
2020-12-07 16:00:45 +01:00
|
|
|
if (cursor.bytesLeft() == 0) {
|
|
|
|
nextCursor();
|
|
|
|
if (cursor.readLong()) {
|
|
|
|
return cursor.getLong();
|
|
|
|
}
|
|
|
|
}
|
2020-11-06 13:39:21 +01:00
|
|
|
long val = 0;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2020-12-07 14:56:03 +01:00
|
|
|
readByte();
|
2020-11-06 13:39:21 +01:00
|
|
|
val <<= 8;
|
2020-12-02 14:29:40 +01:00
|
|
|
val |= getByte();
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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-07 16:00:45 +01:00
|
|
|
if (cursor.readByte()) {
|
|
|
|
byteValue = cursor.getByte();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (bytesLeft() > 0) {
|
|
|
|
nextCursor();
|
|
|
|
cursor.readByte();
|
2020-12-02 14:29:40 +01:00
|
|
|
byteValue = cursor.getByte();
|
|
|
|
return true;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
2020-12-02 14:29:40 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-07 16:00:45 +01:00
|
|
|
private void nextCursor() {
|
|
|
|
bufferIndex--;
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer nextBuf = bufs[bufferIndex];
|
2020-12-07 16:00:45 +01:00
|
|
|
int length = Math.min(nextBuf.capacity(), bytesLeft());
|
|
|
|
int offset = nextBuf.capacity() - 1;
|
|
|
|
cursor = nextBuf.openReverseCursor(offset, length);
|
|
|
|
initOffset = offset;
|
|
|
|
}
|
|
|
|
|
2020-12-02 14:29:40 +01:00
|
|
|
@Override
|
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
2020-12-07 16:00:45 +01:00
|
|
|
int currOff = cursor.currentOffset();
|
|
|
|
index -= initOffset - currOff;
|
|
|
|
initOffset = currOff;
|
2020-11-06 13:39:21 +01:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
2020-12-07 16:00:45 +01:00
|
|
|
return currentOffset() - end;
|
2020-11-06 13:39:21 +01:00
|
|
|
}
|
|
|
|
};
|
2020-10-30 14:39:50 +01:00
|
|
|
}
|
|
|
|
|
2020-11-16 18:00:32 +01:00
|
|
|
@Override
|
2020-12-16 16:44:20 +01:00
|
|
|
public void ensureWritable(int size, boolean allowCompaction) {
|
2020-11-16 18:00:32 +01:00
|
|
|
if (!isOwned()) {
|
|
|
|
throw new IllegalStateException("Buffer is not owned. Only owned buffers can call ensureWritable.");
|
|
|
|
}
|
|
|
|
if (size < 0) {
|
|
|
|
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (readOnly) {
|
|
|
|
throw bufferIsReadOnly();
|
|
|
|
}
|
2020-12-16 16:44:20 +01:00
|
|
|
if (writableBytes() >= size) {
|
|
|
|
// We already have enough space.
|
|
|
|
return;
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
2020-12-16 16:44:20 +01:00
|
|
|
|
|
|
|
if (allowCompaction && size <= roff) {
|
|
|
|
// Let's see if we can solve some or all of the requested size with compaction.
|
|
|
|
// We always compact as much as is possible, regardless of size. This amortizes our work.
|
|
|
|
int compactableBuffers = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-12-16 16:44:20 +01:00
|
|
|
if (buf.capacity() != buf.readerOffset()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
compactableBuffers++;
|
|
|
|
}
|
|
|
|
if (compactableBuffers > 0) {
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer[] compactable;
|
2020-12-16 16:44:20 +01:00
|
|
|
if (compactableBuffers < bufs.length) {
|
2021-02-12 18:22:07 +01:00
|
|
|
compactable = new Buffer[compactableBuffers];
|
2020-12-16 16:44:20 +01:00
|
|
|
System.arraycopy(bufs, 0, compactable, 0, compactable.length);
|
|
|
|
System.arraycopy(bufs, compactable.length, bufs, 0, bufs.length - compactable.length);
|
|
|
|
System.arraycopy(compactable, 0, bufs, bufs.length - compactable.length, compactable.length);
|
|
|
|
} else {
|
|
|
|
compactable = bufs;
|
|
|
|
}
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : compactable) {
|
2020-12-16 16:44:20 +01:00
|
|
|
buf.reset();
|
|
|
|
}
|
|
|
|
computeBufferOffsets();
|
|
|
|
if (writableBytes() >= size) {
|
|
|
|
// Now we have enough space.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long newSize = capacity() + (long) size;
|
2021-02-12 18:22:07 +01:00
|
|
|
BufferAllocator.checkSize(newSize);
|
2020-12-16 16:44:20 +01:00
|
|
|
int growth = size - writableBytes();
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer extension = bufs.length == 0? allocator.allocate(growth) : allocator.allocate(growth, order());
|
2020-12-16 16:44:20 +01:00
|
|
|
unsafeExtendWith(extension);
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
void extendWith(Buffer extension) {
|
2020-12-03 17:48:28 +01:00
|
|
|
Objects.requireNonNull(extension, "Extension buffer cannot be null.");
|
|
|
|
if (!isOwned()) {
|
|
|
|
throw new IllegalStateException("This buffer cannot be extended because it is not in an owned state.");
|
|
|
|
}
|
|
|
|
if (bufs.length > 0 && extension.order() != order()) {
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
"This buffer uses " + order() + " byte order, and cannot be extended with " +
|
|
|
|
"a buffer that uses " + extension.order() + " byte order.");
|
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (bufs.length > 0 && extension.readOnly() != readOnly()) {
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
"This buffer is " + (readOnly? "read-only" : "writable") + ", " +
|
|
|
|
"and cannot be extended with a buffer that is " +
|
|
|
|
(extension.readOnly()? "read-only." : "writable."));
|
2020-12-08 19:25:53 +01:00
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
|
2021-01-15 15:54:03 +01:00
|
|
|
long extensionCapacity = extension.capacity();
|
|
|
|
if (extensionCapacity == 0) {
|
|
|
|
// Extending by a zero-sized buffer makes no difference. Especially since it's not allowed to change the
|
|
|
|
// capacity of buffers that are constiuents of composite buffers.
|
2021-01-18 10:56:33 +01:00
|
|
|
// This also ensures that methods like countComponents, and forEachReadable, do not have to worry about
|
|
|
|
// overflow in their component counters.
|
2021-01-15 15:54:03 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
long newSize = capacity() + extensionCapacity;
|
2021-02-12 18:22:07 +01:00
|
|
|
BufferAllocator.checkSize(newSize);
|
2020-12-03 17:48:28 +01:00
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer[] restoreTemp = bufs; // We need this to restore our buffer array, in case offset computations fail.
|
2020-12-03 17:48:28 +01:00
|
|
|
try {
|
2021-02-12 18:22:07 +01:00
|
|
|
if (extension instanceof CompositeBuffer) {
|
2021-01-18 16:06:53 +01:00
|
|
|
// If the extension is itself a composite buffer, then extend this one by all of the constituent
|
|
|
|
// component buffers.
|
2021-02-12 18:22:07 +01:00
|
|
|
CompositeBuffer compositeExtension = (CompositeBuffer) extension;
|
|
|
|
Buffer[] addedBuffers = compositeExtension.bufs;
|
|
|
|
Set<Buffer> duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>());
|
2021-01-18 16:06:53 +01:00
|
|
|
duplicatesCheck.addAll(Arrays.asList(bufs));
|
|
|
|
duplicatesCheck.addAll(Arrays.asList(addedBuffers));
|
|
|
|
if (duplicatesCheck.size() < bufs.length + addedBuffers.length) {
|
|
|
|
throw extensionDuplicatesException();
|
|
|
|
}
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer addedBuffer : addedBuffers) {
|
2021-01-18 16:06:53 +01:00
|
|
|
addedBuffer.acquire();
|
|
|
|
}
|
|
|
|
int extendAtIndex = bufs.length;
|
|
|
|
bufs = Arrays.copyOf(bufs, extendAtIndex + addedBuffers.length);
|
|
|
|
System.arraycopy(addedBuffers, 0, bufs, extendAtIndex, addedBuffers.length);
|
|
|
|
computeBufferOffsets();
|
|
|
|
} else {
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : restoreTemp) {
|
2021-01-18 16:06:53 +01:00
|
|
|
if (buf == extension) {
|
|
|
|
throw extensionDuplicatesException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsafeExtendWith(extension.acquire());
|
|
|
|
}
|
2021-01-05 16:53:21 +01:00
|
|
|
if (restoreTemp.length == 0) {
|
|
|
|
order = extension.order();
|
|
|
|
readOnly = extension.readOnly();
|
|
|
|
}
|
2020-12-03 17:48:28 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
bufs = restoreTemp;
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:06:53 +01:00
|
|
|
private static IllegalArgumentException extensionDuplicatesException() {
|
|
|
|
return new IllegalArgumentException(
|
|
|
|
"The composite buffer cannot be extended with the given extension," +
|
|
|
|
" as it would cause the buffer to have duplicate constituent buffers.");
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private void unsafeExtendWith(Buffer extension) {
|
2020-12-03 17:48:28 +01:00
|
|
|
bufs = Arrays.copyOf(bufs, bufs.length + 1);
|
|
|
|
bufs[bufs.length - 1] = extension;
|
|
|
|
computeBufferOffsets();
|
|
|
|
}
|
|
|
|
|
2020-12-08 19:25:53 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer bifurcate() {
|
2020-12-08 19:25:53 +01:00
|
|
|
if (!isOwned()) {
|
|
|
|
throw new IllegalStateException("Cannot bifurcate a buffer that is not owned.");
|
|
|
|
}
|
|
|
|
if (bufs.length == 0) {
|
|
|
|
// Bifurcating a zero-length buffer is trivial.
|
2021-03-16 17:22:41 +01:00
|
|
|
return new CompositeBuffer(allocator, bufs, unsafeGetDrop(), true).order(order);
|
2020-12-08 19:25:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int i = searchOffsets(woff);
|
|
|
|
int off = woff - offsets[i];
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer[] bifs = Arrays.copyOf(bufs, off == 0? i : 1 + i);
|
2020-12-08 19:25:53 +01:00
|
|
|
bufs = Arrays.copyOfRange(bufs, off == bufs[i].capacity()? 1 + i : i, bufs.length);
|
|
|
|
if (off > 0 && bifs.length > 0 && off < bifs[bifs.length - 1].capacity()) {
|
|
|
|
bifs[bifs.length - 1] = bufs[0].bifurcate();
|
|
|
|
}
|
|
|
|
computeBufferOffsets();
|
|
|
|
try {
|
2021-03-16 17:22:41 +01:00
|
|
|
var compositeBuf = new CompositeBuffer(allocator, bifs, unsafeGetDrop(), true);
|
2020-12-08 19:25:53 +01:00
|
|
|
compositeBuf.order = order; // Preserve byte order even if bifs array is empty.
|
|
|
|
return compositeBuf;
|
|
|
|
} finally {
|
|
|
|
// Drop our references to the buffers in the bifs array. They belong to the new composite buffer now.
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer bif : bifs) {
|
2020-12-08 19:25:53 +01:00
|
|
|
bif.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 17:01:39 +01:00
|
|
|
@Override
|
|
|
|
public void compact() {
|
|
|
|
if (!isOwned()) {
|
|
|
|
throw new IllegalStateException("Buffer must be owned in order to compact.");
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
int pos = 0;
|
|
|
|
var oldOrder = order;
|
|
|
|
order = ByteOrder.BIG_ENDIAN;
|
|
|
|
try {
|
|
|
|
var cursor = openCursor();
|
|
|
|
while (cursor.readLong()) {
|
|
|
|
setLong(pos, cursor.getLong());
|
|
|
|
pos += Long.BYTES;
|
|
|
|
}
|
|
|
|
while (cursor.readByte()) {
|
|
|
|
setByte(pos, cursor.getByte());
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
order = oldOrder;
|
|
|
|
}
|
|
|
|
readerOffset(0);
|
|
|
|
writerOffset(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
|
|
|
int sum = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2021-01-15 15:54:03 +01:00
|
|
|
sum += buf.countComponents();
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-01-15 15:54:03 +01:00
|
|
|
public int countReadableComponents() {
|
|
|
|
int sum = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2021-01-15 15:54:03 +01:00
|
|
|
sum += buf.countReadableComponents();
|
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countWritableComponents() {
|
|
|
|
int sum = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2021-01-15 15:54:03 +01:00
|
|
|
sum += buf.countWritableComponents();
|
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
|
|
checkReadBounds(readerOffset(), Math.max(1, readableBytes()));
|
|
|
|
int visited = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2021-01-11 16:10:00 +01:00
|
|
|
if (buf.readableBytes() > 0) {
|
2021-01-15 15:54:03 +01:00
|
|
|
int count = buf.forEachReadable(visited + initialIndex, processor);
|
|
|
|
if (count > 0) {
|
|
|
|
visited += count;
|
|
|
|
} else {
|
|
|
|
visited = -visited + count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return visited;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
|
|
checkWriteBounds(writerOffset(), Math.max(1, writableBytes()));
|
|
|
|
int visited = 0;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2021-01-15 15:54:03 +01:00
|
|
|
if (buf.writableBytes() > 0) {
|
|
|
|
int count = buf.forEachWritable(visited + initialIndex, processor);
|
|
|
|
if (count > 0) {
|
|
|
|
visited += count;
|
|
|
|
} else {
|
|
|
|
visited = -visited + count;
|
|
|
|
break;
|
|
|
|
}
|
2021-01-11 16:10:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return visited;
|
|
|
|
}
|
|
|
|
|
2020-10-28 14:38:14 +01:00
|
|
|
// <editor-fold defaultstate="collapsed" desc="Primitive accessors.">
|
|
|
|
@Override
|
|
|
|
public byte readByte() {
|
|
|
|
return prepRead(Byte.BYTES).readByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public byte getByte(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Byte.BYTES).getByte(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedByte() {
|
|
|
|
return prepRead(Byte.BYTES).readUnsignedByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedByte(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Byte.BYTES).getUnsignedByte(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeByte(byte value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Byte.BYTES).writeByte(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setByte(int woff, byte value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Byte.BYTES).setByte(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedByte(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Byte.BYTES).writeUnsignedByte(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedByte(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Byte.BYTES).setUnsignedByte(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char readChar() {
|
|
|
|
return prepRead(2).readChar();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public char getChar(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, 2).getChar(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeChar(char value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(2).writeChar(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setChar(int woff, char value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, 2).setChar(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public short readShort() {
|
|
|
|
return prepRead(Short.BYTES).readShort();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public short getShort(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Short.BYTES).getShort(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedShort() {
|
|
|
|
return prepRead(Short.BYTES).readShort();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedShort(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Short.BYTES).getUnsignedShort(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeShort(short value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Short.BYTES).writeShort(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setShort(int woff, short value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Short.BYTES).setShort(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedShort(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Short.BYTES).writeUnsignedShort(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedShort(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Short.BYTES).setUnsignedShort(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readMedium() {
|
|
|
|
return prepRead(3).readMedium();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getMedium(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, 3).getMedium(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedMedium() {
|
|
|
|
return prepRead(3).readMedium();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedMedium(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, 3).getMedium(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeMedium(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(3).writeMedium(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setMedium(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, 3).setMedium(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedMedium(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(3).writeUnsignedMedium(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedMedium(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, 3).setUnsignedMedium(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readInt() {
|
|
|
|
return prepRead(Integer.BYTES).readInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getInt(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Integer.BYTES).getInt(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readUnsignedInt() {
|
|
|
|
return prepRead(Integer.BYTES).readUnsignedInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getUnsignedInt(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Integer.BYTES).getUnsignedInt(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeInt(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Integer.BYTES).writeInt(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setInt(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Integer.BYTES).setInt(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedInt(long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Integer.BYTES).writeUnsignedInt(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedInt(int woff, long value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Integer.BYTES).setUnsignedInt(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float readFloat() {
|
|
|
|
return prepRead(Float.BYTES).readFloat();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public float getFloat(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Float.BYTES).getFloat(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeFloat(float value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Float.BYTES).writeFloat(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setFloat(int woff, float value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Float.BYTES).setFloat(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readLong() {
|
|
|
|
return prepRead(Long.BYTES).readLong();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getLong(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Long.BYTES).getLong(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeLong(long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Long.BYTES).writeLong(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setLong(int woff, long value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Long.BYTES).setLong(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double readDouble() {
|
|
|
|
return prepRead(Double.BYTES).readDouble();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public double getDouble(int roff) {
|
2021-03-09 12:02:46 +01:00
|
|
|
return prepGet(roff, Double.BYTES).getDouble(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeDouble(double value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
prepWrite(Double.BYTES).writeDouble(value);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setDouble(int woff, double value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
prepWrite(woff, Double.BYTES).setDouble(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
// </editor-fold>
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
protected Owned<CompositeBuffer> prepareSend() {
|
2020-10-28 14:38:14 +01:00
|
|
|
@SuppressWarnings("unchecked")
|
2021-02-12 18:22:07 +01:00
|
|
|
Send<Buffer>[] sends = new Send[bufs.length];
|
2020-10-28 14:38:14 +01:00
|
|
|
try {
|
|
|
|
for (int i = 0; i < bufs.length; i++) {
|
|
|
|
sends[i] = bufs[i].send();
|
|
|
|
}
|
|
|
|
} catch (Throwable throwable) {
|
|
|
|
// Repair our bufs array.
|
|
|
|
for (int i = 0; i < sends.length; i++) {
|
|
|
|
if (sends[i] != null) {
|
|
|
|
try {
|
|
|
|
bufs[i] = sends[i].receive();
|
|
|
|
} catch (Exception e) {
|
|
|
|
throwable.addSuppressed(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw throwable;
|
|
|
|
}
|
2021-03-18 15:18:22 +01:00
|
|
|
boolean readOnly = this.readOnly;
|
2020-12-14 14:07:11 +01:00
|
|
|
makeInaccessible();
|
2021-02-12 18:22:07 +01:00
|
|
|
return new Owned<CompositeBuffer>() {
|
2020-10-28 14:38:14 +01:00
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public CompositeBuffer transferOwnership(Drop<CompositeBuffer> drop) {
|
|
|
|
Buffer[] received = new Buffer[sends.length];
|
2020-10-28 14:38:14 +01:00
|
|
|
for (int i = 0; i < sends.length; i++) {
|
|
|
|
received[i] = sends[i].receive();
|
|
|
|
}
|
2021-03-16 17:22:41 +01:00
|
|
|
var composite = new CompositeBuffer(allocator, received, drop, true);
|
2021-01-05 16:53:21 +01:00
|
|
|
composite.readOnly = readOnly;
|
2020-12-10 12:51:18 +01:00
|
|
|
drop.attach(composite);
|
2020-10-28 14:38:14 +01:00
|
|
|
return composite;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-12-14 14:07:11 +01:00
|
|
|
void makeInaccessible() {
|
|
|
|
capacity = 0;
|
|
|
|
roff = 0;
|
|
|
|
woff = 0;
|
2021-03-18 15:18:22 +01:00
|
|
|
readOnly = false;
|
2020-12-14 14:07:11 +01:00
|
|
|
closed = true;
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:21:20 +01:00
|
|
|
@Override
|
2020-11-16 18:00:32 +01:00
|
|
|
public boolean isOwned() {
|
2021-03-16 17:22:41 +01:00
|
|
|
return super.isOwned() && allConstituentsAreOwned();
|
2020-11-16 18:00:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean allConstituentsAreOwned() {
|
|
|
|
boolean result = true;
|
2021-02-12 18:22:07 +01:00
|
|
|
for (Buffer buf : bufs) {
|
2020-11-16 18:00:32 +01:00
|
|
|
result &= buf.isOwned();
|
|
|
|
}
|
|
|
|
return result;
|
2020-10-30 14:21:20 +01:00
|
|
|
}
|
2020-10-28 14:38:14 +01:00
|
|
|
|
|
|
|
long readPassThrough() {
|
|
|
|
var buf = choosePassThroughBuffer(subOffset++);
|
|
|
|
assert buf != tornBufAccessors: "Recursive call to torn buffer.";
|
|
|
|
return buf.readUnsignedByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
void writePassThrough(int value) {
|
|
|
|
var buf = choosePassThroughBuffer(subOffset++);
|
|
|
|
assert buf != tornBufAccessors: "Recursive call to torn buffer.";
|
|
|
|
buf.writeUnsignedByte(value);
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:00:08 +01:00
|
|
|
long getPassThrough(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
var buf = chooseBuffer(roff, 1);
|
|
|
|
assert buf != tornBufAccessors: "Recursive call to torn buffer.";
|
2020-11-11 23:00:08 +01:00
|
|
|
return buf.getUnsignedByte(subOffset);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2020-11-11 23:00:08 +01:00
|
|
|
void setPassThrough(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
var buf = chooseBuffer(woff, 1);
|
|
|
|
assert buf != tornBufAccessors: "Recursive call to torn buffer.";
|
2020-11-11 23:00:08 +01:00
|
|
|
buf.setUnsignedByte(subOffset, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors prepRead(int size) {
|
2020-10-28 14:38:14 +01:00
|
|
|
var buf = prepRead(roff, size);
|
|
|
|
roff += size;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors prepRead(int index, int size) {
|
2020-10-28 14:38:14 +01:00
|
|
|
checkReadBounds(index, size);
|
|
|
|
return chooseBuffer(index, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkReadBounds(int index, int size) {
|
|
|
|
if (index < 0 || woff < index + size) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(index, false);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-09 12:02:46 +01:00
|
|
|
private BufferAccessors prepGet(int index, int size) {
|
|
|
|
checkGetBounds(index, size);
|
|
|
|
return chooseBuffer(index, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkGetBounds(int index, int size) {
|
|
|
|
if (index < 0 || capacity < index + size) {
|
|
|
|
throw indexOutOfBounds(index, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors prepWrite(int size) {
|
2020-10-28 14:38:14 +01:00
|
|
|
var buf = prepWrite(woff, size);
|
|
|
|
woff += size;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors prepWrite(int index, int size) {
|
2020-10-28 14:38:14 +01:00
|
|
|
checkWriteBounds(index, size);
|
|
|
|
return chooseBuffer(index, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkWriteBounds(int index, int size) {
|
|
|
|
if (index < 0 || capacity < index + size) {
|
2021-01-05 16:53:21 +01:00
|
|
|
throw indexOutOfBounds(index, true);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-05 16:53:21 +01:00
|
|
|
private RuntimeException indexOutOfBounds(int index, boolean write) {
|
2020-12-14 14:07:11 +01:00
|
|
|
if (closed) {
|
2021-01-05 16:53:21 +01:00
|
|
|
return bufferIsClosed();
|
|
|
|
}
|
|
|
|
if (write && readOnly) {
|
|
|
|
return bufferIsReadOnly();
|
2020-12-14 14:07:11 +01:00
|
|
|
}
|
2020-10-28 14:38:14 +01:00
|
|
|
return new IndexOutOfBoundsException(
|
|
|
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
2021-03-09 16:16:38 +01:00
|
|
|
capacity + "].");
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2021-01-05 16:53:21 +01:00
|
|
|
private static IllegalStateException bufferIsClosed() {
|
|
|
|
return new IllegalStateException("This buffer is closed.");
|
|
|
|
}
|
|
|
|
|
|
|
|
private static IllegalStateException bufferIsReadOnly() {
|
|
|
|
return new IllegalStateException("This buffer is read-only.");
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors chooseBuffer(int index, int size) {
|
2020-10-28 14:38:14 +01:00
|
|
|
int i = searchOffsets(index);
|
|
|
|
if (i == bufs.length) {
|
|
|
|
// This happens when the read/write offsets are parked 1 byte beyond the end of the buffer.
|
|
|
|
// In that case it should not matter what buffer is returned, because it shouldn't be used anyway.
|
|
|
|
return null;
|
|
|
|
}
|
2020-11-05 15:15:34 +01:00
|
|
|
int off = index - offsets[i];
|
2021-02-12 18:22:07 +01:00
|
|
|
Buffer candidate = bufs[i];
|
2020-10-28 14:38:14 +01:00
|
|
|
if (off + size <= candidate.capacity()) {
|
|
|
|
subOffset = off;
|
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
subOffset = index;
|
|
|
|
return tornBufAccessors;
|
|
|
|
}
|
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private BufferAccessors choosePassThroughBuffer(int index) {
|
2020-10-28 14:38:14 +01:00
|
|
|
int i = searchOffsets(index);
|
|
|
|
return bufs[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
private int searchOffsets(int index) {
|
|
|
|
int i = Arrays.binarySearch(offsets, index);
|
2020-11-17 15:25:26 +01:00
|
|
|
return i < 0? -(i + 2) : i;
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
2020-11-05 15:15:34 +01:00
|
|
|
// <editor-fold defaultstate="collapsed" desc="Torn buffer access.">
|
2021-02-12 18:22:07 +01:00
|
|
|
private static final class TornBufferAccessors implements BufferAccessors {
|
|
|
|
private final CompositeBuffer buf;
|
2020-10-28 14:38:14 +01:00
|
|
|
|
2021-02-12 18:22:07 +01:00
|
|
|
private TornBufferAccessors(CompositeBuffer buf) {
|
2020-10-28 14:38:14 +01:00
|
|
|
this.buf = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte readByte() {
|
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public byte getByte(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedByte() {
|
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedByte(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeByte(byte value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setByte(int woff, byte value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedByte(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedByte(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
throw new AssertionError("Method should not be used.");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char readChar() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (char) (read() << 8 | read());
|
|
|
|
} else {
|
|
|
|
return (char) (read() | read() << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public char getChar(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (char) (read(roff) << 8 | read(roff + 1));
|
|
|
|
} else {
|
|
|
|
return (char) (read(roff) | read(roff + 1) << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeChar(char value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 8);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setChar(int woff, char value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 8);
|
|
|
|
write(woff + 1, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public short readShort() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (short) (read() << 8 | read());
|
|
|
|
} else {
|
|
|
|
return (short) (read() | read() << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public short getShort(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (short) (read(roff) << 8 | read(roff + 1));
|
|
|
|
} else {
|
|
|
|
return (short) (read(roff) | read(roff + 1) << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedShort() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read() << 8 | read()) & 0xFFFF;
|
|
|
|
} else {
|
|
|
|
return (int) (read() | read() << 8) & 0xFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedShort(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read(roff) << 8 | read(roff + 1)) & 0xFFFF;
|
|
|
|
} else {
|
|
|
|
return (int) (read(roff) | read(roff + 1) << 8) & 0xFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeShort(short value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 8);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setShort(int woff, short value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 8);
|
|
|
|
write(woff + 1, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedShort(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 8);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedShort(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 8);
|
|
|
|
write(woff + 1, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readMedium() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read() << 16 | read() << 8 | read());
|
|
|
|
} else {
|
|
|
|
return (int) (read() | read() << 8 | read() << 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getMedium(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2));
|
|
|
|
} else {
|
|
|
|
return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedMedium() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read() << 16 | read() << 8 | read()) & 0xFFFFFF;
|
|
|
|
} else {
|
|
|
|
return (int) (read() | read() << 8 | read() << 16) & 0xFFFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getUnsignedMedium(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2)) & 0xFFFFFF;
|
|
|
|
} else {
|
|
|
|
return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16) & 0xFFFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeMedium(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 16);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value >>> 16);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setMedium(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 16);
|
|
|
|
write(woff + 1, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 2, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 2, value >>> 16);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedMedium(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 16);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value >>> 16);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedMedium(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 16);
|
|
|
|
write(woff + 1, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 2, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 2, value >>> 16);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readInt() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read() << 24 | read() << 16 | read() << 8 | read());
|
|
|
|
} else {
|
|
|
|
return (int) (read() | read() << 8 | read() << 16 | read() << 24);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public int getInt(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (int) (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3));
|
|
|
|
} else {
|
|
|
|
return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readUnsignedInt() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return (read() << 24 | read() << 16 | read() << 8 | read()) & 0xFFFFFFFFL;
|
|
|
|
} else {
|
|
|
|
return (read() | read() << 8 | read() << 16 | read() << 24) & 0xFFFFFFFFL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getUnsignedInt(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3)) & 0xFFFFFFFFL;
|
|
|
|
} else {
|
|
|
|
return (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24) & 0xFFFFFFFFL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeInt(int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(value >>> 24);
|
|
|
|
write(value >>> 16 & 0xFF);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(value & 0xFF);
|
|
|
|
write(value >>> 8 & 0xFF);
|
|
|
|
write(value >>> 16 & 0xFF);
|
|
|
|
write(value >>> 24);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setInt(int woff, int value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, value >>> 24);
|
|
|
|
write(woff + 1, value >>> 16 & 0xFF);
|
|
|
|
write(woff + 2, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 3, value & 0xFF);
|
|
|
|
} else {
|
|
|
|
write(woff, value & 0xFF);
|
|
|
|
write(woff + 1, value >>> 8 & 0xFF);
|
|
|
|
write(woff + 2, value >>> 16 & 0xFF);
|
|
|
|
write(woff + 3, value >>> 24);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeUnsignedInt(long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write((int) (value >>> 24));
|
|
|
|
write((int) (value >>> 16 & 0xFF));
|
|
|
|
write((int) (value >>> 8 & 0xFF));
|
|
|
|
write((int) (value & 0xFF));
|
|
|
|
} else {
|
|
|
|
write((int) (value & 0xFF));
|
|
|
|
write((int) (value >>> 8 & 0xFF));
|
|
|
|
write((int) (value >>> 16 & 0xFF));
|
|
|
|
write((int) (value >>> 24));
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setUnsignedInt(int woff, long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, (int) (value >>> 24));
|
|
|
|
write(woff + 1, (int) (value >>> 16 & 0xFF));
|
|
|
|
write(woff + 2, (int) (value >>> 8 & 0xFF));
|
|
|
|
write(woff + 3, (int) (value & 0xFF));
|
|
|
|
} else {
|
|
|
|
write(woff, (int) (value & 0xFF));
|
|
|
|
write(woff + 1, (int) (value >>> 8 & 0xFF));
|
|
|
|
write(woff + 2, (int) (value >>> 16 & 0xFF));
|
|
|
|
write(woff + 3, (int) (value >>> 24));
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float readFloat() {
|
|
|
|
return Float.intBitsToFloat(readInt());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public float getFloat(int roff) {
|
|
|
|
return Float.intBitsToFloat(getInt(roff));
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeFloat(float value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
return writeUnsignedInt(Float.floatToRawIntBits(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setFloat(int woff, float value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
return setUnsignedInt(woff, Float.floatToRawIntBits(value));
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readLong() {
|
|
|
|
if (bigEndian()) {
|
|
|
|
return read() << 56 | read() << 48 | read() << 40 | read() << 32 |
|
|
|
|
read() << 24 | read() << 16 | read() << 8 | read();
|
|
|
|
} else {
|
|
|
|
return read() | read() << 8 | read() << 16 | read() << 24 |
|
|
|
|
read() << 32 | read() << 40 | read() << 48 | read() << 56;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public long getLong(int roff) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
return read(roff) << 56 | read(roff + 1) << 48 | read(roff + 2) << 40 | read(roff + 3) << 32 |
|
|
|
|
read(roff + 4) << 24 | read(roff + 5) << 16 | read(roff + 6) << 8 | read(roff + 7);
|
|
|
|
} else {
|
|
|
|
return read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24 |
|
|
|
|
read(roff + 4) << 32 | read(roff + 5) << 40 | read(roff + 6) << 48 | read(roff + 7) << 56;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeLong(long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write((int) (value >>> 56));
|
|
|
|
write((int) (value >>> 48 & 0xFF));
|
|
|
|
write((int) (value >>> 40 & 0xFF));
|
|
|
|
write((int) (value >>> 32 & 0xFF));
|
|
|
|
write((int) (value >>> 24 & 0xFF));
|
|
|
|
write((int) (value >>> 16 & 0xFF));
|
|
|
|
write((int) (value >>> 8 & 0xFF));
|
|
|
|
write((int) (value & 0xFF));
|
|
|
|
} else {
|
|
|
|
write((int) (value & 0xFF));
|
|
|
|
write((int) (value >>> 8 & 0xFF));
|
|
|
|
write((int) (value >>> 16 & 0xFF));
|
|
|
|
write((int) (value >>> 24));
|
|
|
|
write((int) (value >>> 32));
|
|
|
|
write((int) (value >>> 40));
|
|
|
|
write((int) (value >>> 48));
|
|
|
|
write((int) (value >>> 56));
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setLong(int woff, long value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
if (bigEndian()) {
|
|
|
|
write(woff, (int) (value >>> 56));
|
|
|
|
write(woff + 1, (int) (value >>> 48 & 0xFF));
|
|
|
|
write(woff + 2, (int) (value >>> 40 & 0xFF));
|
|
|
|
write(woff + 3, (int) (value >>> 32 & 0xFF));
|
|
|
|
write(woff + 4, (int) (value >>> 24 & 0xFF));
|
|
|
|
write(woff + 5, (int) (value >>> 16 & 0xFF));
|
|
|
|
write(woff + 6, (int) (value >>> 8 & 0xFF));
|
|
|
|
write(woff + 7, (int) (value & 0xFF));
|
|
|
|
} else {
|
|
|
|
write(woff, (int) (value & 0xFF));
|
|
|
|
write(woff + 1, (int) (value >>> 8 & 0xFF));
|
|
|
|
write(woff + 2, (int) (value >>> 16 & 0xFF));
|
|
|
|
write(woff + 3, (int) (value >>> 24));
|
|
|
|
write(woff + 4, (int) (value >>> 32));
|
|
|
|
write(woff + 5, (int) (value >>> 40));
|
|
|
|
write(woff + 6, (int) (value >>> 48));
|
|
|
|
write(woff + 7, (int) (value >>> 56));
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double readDouble() {
|
|
|
|
return Double.longBitsToDouble(readLong());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-11-11 23:00:08 +01:00
|
|
|
public double getDouble(int roff) {
|
|
|
|
return Double.longBitsToDouble(getLong(roff));
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer writeDouble(double value) {
|
2020-10-28 14:38:14 +01:00
|
|
|
return writeLong(Double.doubleToRawLongBits(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-02-12 18:22:07 +01:00
|
|
|
public Buffer setDouble(int woff, double value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
return setLong(woff, Double.doubleToRawLongBits(value));
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean bigEndian() {
|
|
|
|
return buf.order() == ByteOrder.BIG_ENDIAN;
|
|
|
|
}
|
|
|
|
|
|
|
|
private long read() {
|
|
|
|
return buf.readPassThrough();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void write(int value) {
|
|
|
|
buf.writePassThrough(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
private long read(int roff) {
|
2020-11-11 23:00:08 +01:00
|
|
|
return buf.getPassThrough(roff);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void write(int woff, int value) {
|
2020-11-11 23:00:08 +01:00
|
|
|
buf.setPassThrough(woff, value);
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|
|
|
|
}
|
2020-11-05 15:15:34 +01:00
|
|
|
// </editor-fold>
|
2020-10-28 14:38:14 +01:00
|
|
|
}
|