Skip to content

Commit a1f65ae

Browse files
committed
Add ByteBank: generic self-growing byte stores
Provides two implementations: - ByteArrayByteBank: backed by org.scjiva.util.ByteArray - ByteBufferByteBank: backed by java.nio.ByteBuffer
1 parent 622af57 commit a1f65ae

File tree

4 files changed

+295
-93
lines changed

4 files changed

+295
-93
lines changed

src/main/java/org/scijava/io/ByteArrayIOBuffer.java renamed to src/main/java/org/scijava/io/bytes/ByteArrayByteBank.java

Lines changed: 56 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
* %%
99
* Redistribution and use in source and binary forms, with or without
1010
* modification, are permitted provided that the following conditions are met:
11-
*
11+
*
1212
* 1. Redistributions of source code must retain the above copyright notice,
1313
* this list of conditions and the following disclaimer.
1414
* 2. Redistributions in binary form must reproduce the above copyright notice,
1515
* this list of conditions and the following disclaimer in the documentation
1616
* and/or other materials provided with the distribution.
17-
*
17+
*
1818
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1919
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2020
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -29,34 +29,70 @@
2929
* #L%
3030
*/
3131

32-
package org.scijava.io;
32+
package org.scijava.io.bytes;
3333

3434
import org.scijava.util.ByteArray;
3535

3636
/**
37-
* {@link IOBuffer} implementation backed by a {@link ByteArray}.
38-
*
37+
* {@link ByteBank} implementation backed by a {@link ByteArray}. Self-growing
38+
* up to a maximum capacity of {@link Integer#MAX_VALUE}
39+
*
3940
* @author Gabriel Einsdorf
4041
*/
41-
public class ByteArrayIOBuffer implements IOBuffer {
42+
public class ByteArrayByteBank implements ByteBank {
4243

43-
private ByteArray buffer;
44+
private final ByteArray buffer;
4445
private long maxBufferedPos = -1;
4546

46-
public ByteArrayIOBuffer() {
47+
/**
48+
* Creates a {@link ByteArrayByteBank}
49+
*/
50+
public ByteArrayByteBank() {
4751
buffer = new ByteArray();
4852
}
4953

54+
/**
55+
* Creates a {@link ByteArrayByteBank} with the specified initial capacity
56+
*
57+
* @param initialCapacity the initial capacity of this {@link ByteBank}
58+
*/
59+
public ByteArrayByteBank(final int initialCapacity) {
60+
buffer = new ByteArray(initialCapacity);
61+
}
62+
63+
/**
64+
* Creates a {@link ByteArrayByteBank} that wraps the specified
65+
* {@link ByteArray}.
66+
*
67+
* @param bytes the {@link ByteArray} to wrap
68+
*/
69+
public ByteArrayByteBank(final ByteArray bytes) {
70+
buffer = bytes;
71+
bytes.size();
72+
}
73+
74+
/**
75+
* Creates a {@link ByteArrayByteBank} that wraps the provided byte array
76+
*
77+
* @param bytes the bytes to wrap
78+
*/
79+
public ByteArrayByteBank(final byte[] bytes) {
80+
buffer = new ByteArray(bytes);
81+
maxBufferedPos = bytes.length;
82+
}
83+
5084
@Override
51-
public int getMaxBufferSize() {
85+
public long getMaxBufferSize() {
5286
return Integer.MAX_VALUE;
5387
}
5488

5589
@Override
56-
public void setBytes(long startpos, byte[] bytes, int offset, int length) {
90+
public void setBytes(final long startpos, final byte[] bytes,
91+
final int offset, final int length)
92+
{
5793
// ensure we have space
5894
checkWritePos(startpos, startpos + length);
59-
int neededCapacity = (int) (Math.max(maxBufferedPos, 0) + length);
95+
final int neededCapacity = (int) (Math.max(maxBufferedPos, 0) + length);
6096
buffer.ensureCapacity(neededCapacity);
6197

6298
// copy the data
@@ -66,13 +102,13 @@ public void setBytes(long startpos, byte[] bytes, int offset, int length) {
66102
}
67103

68104
@Override
69-
public void setByte(long pos, byte b) {
105+
public void setByte(final long pos, final byte b) {
70106
checkWritePos(pos, pos);
71107
buffer.setValue((int) pos, b);
72108
updateMaxPos(pos);
73109
}
74110

75-
private void updateMaxPos(long pos) {
111+
private void updateMaxPos(final long pos) {
76112
maxBufferedPos = pos > maxBufferedPos ? pos : maxBufferedPos;
77113
}
78114

@@ -83,77 +119,25 @@ public void clear() {
83119
}
84120

85121
@Override
86-
public byte getByte(long pos) {
122+
public byte getByte(final long pos) {
87123
checkReadPos(pos, pos);
88124
// the buffer might contain bytes with negative value
89125
// we need to flip the sign to positive to satisfy the method contract
90126
return buffer.getValue((int) pos);
91127
}
92128

93129
@Override
94-
public int getBytes(long startPos, byte[] b, int offset, int length) {
130+
public int getBytes(final long startPos, final byte[] b, final int offset,
131+
final int length)
132+
{
95133
checkReadPos(startPos, startPos + length);
96-
System.arraycopy(buffer.getArray(), (int) startPos, b, offset, length);
97-
return length;
134+
final int readLength = (int) Math.min(getMaxPos() - startPos, length);
135+
System.arraycopy(buffer.getArray(), (int) startPos, b, offset, readLength);
136+
return readLength;
98137
}
99138

100139
@Override
101140
public long getMaxPos() {
102141
return maxBufferedPos;
103142
}
104-
105-
/**
106-
* Ensures that the requested range satisfies basic sanity criteria.
107-
*
108-
* @param start the start of the range
109-
* @param end the end of the range
110-
*/
111-
private void basicRangeCheck(long start, long end) {
112-
if (start > Integer.MAX_VALUE) {
113-
throw new IndexOutOfBoundsException("Requested postion " + start +
114-
" is larger than the maximal buffer size: " + Integer.MAX_VALUE);
115-
}
116-
if (end > Integer.MAX_VALUE) {
117-
throw new IndexOutOfBoundsException("Requested postion " + end +
118-
" is larger than the maximal buffer size: " + Integer.MAX_VALUE);
119-
}
120-
if (end < start) {
121-
throw new IllegalArgumentException(
122-
"Invalid range, end is smaller than start!");
123-
}
124-
}
125-
126-
/**
127-
* Check if we can write to the specified range
128-
*
129-
* @param start the start position of the range
130-
* @param end the end position of the range
131-
*/
132-
private void checkWritePos(long start, long end) {
133-
basicRangeCheck(start, end);
134-
if (start > maxBufferedPos + 1) { // we can't have holes in the buffer
135-
throw new IndexOutOfBoundsException("Requested start position: " + start +
136-
" would leave a hole in the buffer, largest legal position is: " +
137-
maxBufferedPos + 1);
138-
}
139-
}
140-
141-
/**
142-
* Check if we can read from the specified range
143-
*
144-
* @param start the start position of the range
145-
* @param end the end position of the range
146-
*/
147-
private void checkReadPos(long start, long end) {
148-
basicRangeCheck(start, end);
149-
if (start > maxBufferedPos) {
150-
throw new IndexOutOfBoundsException("Reuested position: " + start +
151-
" is larger than the maximally buffered postion: " + maxBufferedPos);
152-
}
153-
if (end > maxBufferedPos) {
154-
throw new IndexOutOfBoundsException("reuested position: " + end +
155-
" is larger than the maximally buffered postion: " + maxBufferedPos);
156-
}
157-
}
158-
159143
}

src/main/java/org/scijava/io/IOBuffer.java renamed to src/main/java/org/scijava/io/bytes/ByteBank.java

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
* %%
99
* Redistribution and use in source and binary forms, with or without
1010
* modification, are permitted provided that the following conditions are met:
11-
*
11+
*
1212
* 1. Redistributions of source code must retain the above copyright notice,
1313
* this list of conditions and the following disclaimer.
1414
* 2. Redistributions in binary form must reproduce the above copyright notice,
1515
* this list of conditions and the following disclaimer in the documentation
1616
* and/or other materials provided with the distribution.
17-
*
17+
*
1818
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1919
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2020
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -29,14 +29,14 @@
2929
* #L%
3030
*/
3131

32-
package org.scijava.io;
32+
package org.scijava.io.bytes;
3333

3434
/**
35-
* Self-growing buffer over arbitrary bytes.
36-
*
35+
* A {@link ByteBank} is a self-growing buffer over arbitrary bytes.
36+
*
3737
* @author Gabriel Einsdorf
3838
*/
39-
public interface IOBuffer {
39+
public interface ByteBank {
4040

4141
/**
4242
* @param pos the position to read from
@@ -65,7 +65,7 @@ default int getBytes(long startPos, byte[] bytes) {
6565
/**
6666
* Sets the bytes starting form the given position to the values form the
6767
* provided array.
68-
*
68+
*
6969
* @param startPos the position in the buffer to start writing from
7070
* @param bytes the byte array to write
7171
* @param offset the offset in the bytes array
@@ -75,34 +75,89 @@ default int getBytes(long startPos, byte[] bytes) {
7575

7676
/**
7777
* Appends the given bytes to the buffer
78-
*
79-
* @param bytes the bytes to append to the buffer
78+
*
79+
* @param bytes the array containing the bytes to append to the buffer
8080
* @param length the number of elements to append from the bytes array
8181
*/
8282
default void appendBytes(byte[] bytes, int length) {
8383
setBytes(getMaxPos() + 1, bytes, 0, length);
8484
}
8585

86+
/**
87+
* Check if we can read from the specified range
88+
*
89+
* @param start the start position of the range
90+
* @param end the end position of the range
91+
*/
92+
default void checkReadPos(final long start, final long end) {
93+
basicRangeCheck(start, end);
94+
if (start > getMaxPos()) {
95+
throw new IndexOutOfBoundsException("Requested position: " + start +
96+
" is larger than the maximally buffered postion: " + getMaxPos());
97+
}
98+
}
99+
100+
/**
101+
* Check if we can write to the specified range
102+
*
103+
* @param start the start position of the range
104+
* @param end the end position of the range
105+
* @throws IndexOutOfBoundsException if
106+
*/
107+
default void checkWritePos(final long start, final long end) {
108+
if (start > getMaxPos() + 1) { // we can't have holes in the buffer
109+
throw new IndexOutOfBoundsException("Requested start position: " + start +
110+
" would leave a hole in the buffer, largest legal position is: " +
111+
getMaxPos() + 1);
112+
}
113+
if (end < start) {
114+
throw new IllegalArgumentException(
115+
"Invalid range, end is smaller than start!");
116+
}
117+
if (end > getMaxBufferSize()) {
118+
throw new IndexOutOfBoundsException("Requested postion " + end +
119+
" is larger than the maximal buffer size: " + getMaxPos());
120+
}
121+
}
122+
123+
/**
124+
* Ensures that the requested range satisfies basic sanity criteria.
125+
*
126+
* @param start the start of the range
127+
* @param end the end of the range
128+
*/
129+
default void basicRangeCheck(final long start, final long end) {
130+
if (start > getMaxPos()) {
131+
throw new IndexOutOfBoundsException("Requested postion " + start +
132+
" is larger than the maximal buffer size: " + getMaxPos());
133+
}
134+
if (end < start) {
135+
throw new IllegalArgumentException(
136+
"Invalid range, end is smaller than start!");
137+
}
138+
}
139+
86140
/**
87141
* Clears the buffer
88142
*/
89-
public void clear();
143+
void clear();
90144

91145
/**
92-
* @return the largest bufferd position
146+
* @return the position of the last byte in this ByteBank
93147
*/
94-
public long getMaxPos();
148+
long getMaxPos();
95149

96150
/**
97151
* Sets the byte at the given position
98-
*
152+
*
99153
* @param pos the position
100154
* @param b the value to set
101155
*/
102156
void setByte(long pos, byte b);
103157

104158
/**
105-
* @return the max size of the buffer
159+
* @return the maximal size of the buffer
106160
*/
107-
public int getMaxBufferSize();
161+
long getMaxBufferSize();
162+
108163
}

src/main/java/org/scijava/io/location/DefaultBufferedStreamHandle.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
import org.scijava.io.DataHandleInputStream;
3939
import org.scijava.io.DataHandleOutputStream;
4040
import org.scijava.io.Location;
41-
import org.scijava.io.bytes.ByteArrayIOBuffer;
42-
import org.scijava.io.bytes.IOBuffer;
41+
import org.scijava.io.bytes.ByteArrayByteBank;
42+
import org.scijava.io.bytes.ByteBank;
4343

4444
/**
45-
* A {@link BufferedStreamHandle} backed by an {@link IOBuffer}.
45+
* A {@link BufferedStreamHandle} backed by an {@link ByteBank}.
4646
*
4747
* @author Gabriel Einsdorf
4848
*/
@@ -53,7 +53,7 @@ public class DefaultBufferedStreamHandle<L extends Location> extends
5353
private static final int CHUNK_SIZE = 8192;
5454

5555
private final StreamHandle<L> handle;
56-
private IOBuffer buffer;
56+
private ByteBank buffer;
5757

5858
private InputStream inStreamProxy;
5959
private OutputStream outStreamProxy;
@@ -224,12 +224,12 @@ public void close() throws IOException {
224224
* @return the buffer used in this handle
225225
* @throws IOException if this handle has been closed
226226
*/
227-
private IOBuffer getBufferIfOpen() throws IOException {
227+
private ByteBank getBufferIfOpen() throws IOException {
228228
if (closed) {
229229
throw new IOException("Handle is closed");
230230
}
231231
if (buffer == null) {
232-
buffer = new ByteArrayIOBuffer();
232+
buffer = new ByteArrayByteBank();
233233
}
234234
return buffer;
235235
}

0 commit comments

Comments
 (0)