Merge "Improve DataSource interface." am: ce4c9d7108

am: f41e840250

* commit 'f41e840250e2c0e5cce9263edbcb43fec4163d85':
  Improve DataSource interface.

Change-Id: Ibf017a47be707dbd0576021832ce760a7dcaa21a
This commit is contained in:
Alex Klyubin 2016-05-27 20:12:27 +00:00 committed by android-build-merger
commit fe2470994e
3 changed files with 63 additions and 24 deletions

View File

@ -28,7 +28,7 @@ import java.nio.ByteBuffer;
public class ByteBufferDataSource implements DataSource {
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
@ -45,7 +45,59 @@ public class ByteBufferDataSource implements DataSource {
}
@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) {
throw new IllegalArgumentException("offset: " + offset);
}
@ -65,25 +117,5 @@ public class ByteBufferDataSource implements DataSource {
throw new IllegalArgumentException(
"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);
}
}

View File

@ -43,5 +43,11 @@ public interface DataSource {
* @param offset index (in bytes) at which the chunk starts inside data source
* @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);
}

View File

@ -12,7 +12,8 @@ public abstract class DataSources {
/**
* 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) {
if (buffer == null) {