Merge "Improve DataSource interface."
am: ce4c9d7108
* commit 'ce4c9d71080d27ce321b1aa49e2189ee55bb25fa':
Improve DataSource interface.
Change-Id: I8a1df06ee64785ae48414b2468e760c41d7f41f3
This commit is contained in:
@@ -28,7 +28,7 @@ import java.nio.ByteBuffer;
|
|||||||
public class ByteBufferDataSource implements DataSource {
|
public class ByteBufferDataSource implements DataSource {
|
||||||
|
|
||||||
private final ByteBuffer mBuffer;
|
private final ByteBuffer mBuffer;
|
||||||
private final long mSize;
|
private final int mSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code ByteBufferDigestSource} based on the data contained in the provided
|
* Constructs a new {@code ByteBufferDigestSource} based on the data contained in the provided
|
||||||
@@ -45,7 +45,59 @@ public class ByteBufferDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void feed(long offset, int size, DataSink sink) throws IOException {
|
public ByteBufferDataSource slice(long offset, long size) {
|
||||||
|
if ((offset == 0) && (size == mSize)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
checkChunkValid(offset, size);
|
||||||
|
|
||||||
|
// checkChunkValid ensures that it's OK to cast offset and size to int.
|
||||||
|
int chunkPosition = (int) offset;
|
||||||
|
int chunkLimit = (int) (chunkPosition + size);
|
||||||
|
// Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
|
||||||
|
// and limit fields, to be more specific). We thus use synchronization around these
|
||||||
|
// state-changing operations to make instances of this class thread-safe.
|
||||||
|
synchronized (mBuffer) {
|
||||||
|
// ByteBuffer.limit(int) and .position(int) check that that the position >= limit
|
||||||
|
// invariant is not broken. Thus, the only way to safely change position and limit
|
||||||
|
// without caring about their current values is to first set position to 0 or set the
|
||||||
|
// limit to capacity.
|
||||||
|
mBuffer.position(0);
|
||||||
|
|
||||||
|
mBuffer.limit(chunkLimit);
|
||||||
|
mBuffer.position(chunkPosition);
|
||||||
|
// Create a ByteBufferDataSource for the slice of the buffer between limit and position.
|
||||||
|
return new ByteBufferDataSource(mBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void feed(long offset, long size, DataSink sink) throws IOException {
|
||||||
|
checkChunkValid(offset, size);
|
||||||
|
|
||||||
|
// checkChunkValid ensures that it's OK to cast offset and size to int.
|
||||||
|
int chunkPosition = (int) offset;
|
||||||
|
int chunkLimit = (int) (chunkPosition + size);
|
||||||
|
ByteBuffer chunk;
|
||||||
|
// Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
|
||||||
|
// and limit fields, to be more specific). We thus use synchronization around these
|
||||||
|
// state-changing operations to make instances of this class thread-safe.
|
||||||
|
synchronized (mBuffer) {
|
||||||
|
// ByteBuffer.limit(int) and .position(int) check that that the position >= limit
|
||||||
|
// invariant is not broken. Thus, the only way to safely change position and limit
|
||||||
|
// without caring about their current values is to first set position to 0 or set the
|
||||||
|
// limit to capacity.
|
||||||
|
mBuffer.position(0);
|
||||||
|
|
||||||
|
mBuffer.limit(chunkLimit);
|
||||||
|
mBuffer.position(chunkPosition);
|
||||||
|
chunk = mBuffer.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
sink.consume(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkChunkValid(long offset, long size) {
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
throw new IllegalArgumentException("offset: " + offset);
|
throw new IllegalArgumentException("offset: " + offset);
|
||||||
}
|
}
|
||||||
@@ -65,25 +117,5 @@ public class ByteBufferDataSource implements DataSource {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"offset (" + offset + ") + size (" + size + ") > source size (" + mSize +")");
|
"offset (" + offset + ") + size (" + size + ") > source size (" + mSize +")");
|
||||||
}
|
}
|
||||||
|
|
||||||
int chunkPosition = (int) offset; // safe to downcast because mSize <= Integer.MAX_VALUE
|
|
||||||
int chunkLimit = (int) endOffset; // safe to downcast because mSize <= Integer.MAX_VALUE
|
|
||||||
ByteBuffer chunk;
|
|
||||||
// Creating a slice of ByteBuffer modifies the state of the source ByteBuffer (position
|
|
||||||
// and limit fields, to be more specific). We thus use synchronization around these
|
|
||||||
// state-changing operations to make instances of this class thread-safe.
|
|
||||||
synchronized (mBuffer) {
|
|
||||||
// ByteBuffer.limit(int) and .position(int) check that that the position >= limit
|
|
||||||
// invariant is not broken. Thus, the only way to safely change position and limit
|
|
||||||
// without caring about their current values is to first set position to 0 or set the
|
|
||||||
// limit to capacity.
|
|
||||||
mBuffer.position(0);
|
|
||||||
|
|
||||||
mBuffer.limit(chunkLimit);
|
|
||||||
mBuffer.position(chunkPosition);
|
|
||||||
chunk = mBuffer.slice();
|
|
||||||
}
|
|
||||||
|
|
||||||
sink.consume(chunk);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,5 +43,11 @@ public interface DataSource {
|
|||||||
* @param offset index (in bytes) at which the chunk starts inside data source
|
* @param offset index (in bytes) at which the chunk starts inside data source
|
||||||
* @param size size (in bytes) of the chunk
|
* @param size size (in bytes) of the chunk
|
||||||
*/
|
*/
|
||||||
void feed(long offset, int size, DataSink sink) throws IOException;
|
void feed(long offset, long size, DataSink sink) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data source representing the specified region of data of this data source. Changes
|
||||||
|
* to data represented by this data source will also be visible in the returned data source.
|
||||||
|
*/
|
||||||
|
DataSource slice(long offset, long size);
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,8 @@ public abstract class DataSources {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link DataSource} backed by the provided {@link ByteBuffer}. The data source
|
* Returns a {@link DataSource} backed by the provided {@link ByteBuffer}. The data source
|
||||||
* represents the data contained between the position and limit of the buffer.
|
* represents the data contained between the position and limit of the buffer. Changes to the
|
||||||
|
* buffer's contents will be visible in the data source.
|
||||||
*/
|
*/
|
||||||
public static DataSource asDataSource(ByteBuffer buffer) {
|
public static DataSource asDataSource(ByteBuffer buffer) {
|
||||||
if (buffer == null) {
|
if (buffer == null) {
|
||||||
|
Reference in New Issue
Block a user