Skip to content

Commit c9400f6

Browse files
committed
Add SingleBuffer class that implements Buffer class
1 parent d04d33f commit c9400f6

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package com.maxmind.db;
2+
3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
import java.nio.channels.FileChannel;
6+
import java.nio.channels.FileChannel.MapMode;
7+
import java.nio.charset.CharacterCodingException;
8+
import java.nio.charset.CharsetDecoder;
9+
10+
/**
11+
* A {@link Buffer} implementation backed by a single {@link ByteBuffer}.
12+
*
13+
* <p>This implementation is limited to capacities up to
14+
* {@link Integer#MAX_VALUE}, as {@link ByteBuffer} cannot exceed that size.
15+
*/
16+
public class SingleBuffer implements Buffer {
17+
18+
private final ByteBuffer buffer;
19+
20+
/**
21+
* Creates a new {@code SingleBuffer} with the given capacity.
22+
*
23+
* @param capacity the capacity in bytes (must be <= Integer.MAX_VALUE)
24+
* @throws IllegalArgumentException if the capacity exceeds
25+
* {@link Integer#MAX_VALUE}
26+
*/
27+
public SingleBuffer(long capacity) {
28+
if (capacity > Integer.MAX_VALUE) {
29+
throw new IllegalArgumentException(
30+
"SingleBuffer cannot exceed Integer.MAX_VALUE capacity"
31+
);
32+
}
33+
this.buffer = ByteBuffer.allocate((int) capacity);
34+
}
35+
36+
/**
37+
* Creates a new {@code SingleBuffer} wrapping the given {@link ByteBuffer}.
38+
*
39+
* @param buffer the underlying buffer
40+
*/
41+
private SingleBuffer(ByteBuffer buffer) {
42+
this.buffer = buffer;
43+
}
44+
45+
/**
46+
* Validates and converts a long index to an int for use with
47+
* {@link ByteBuffer}.
48+
*
49+
* @param index the index to check
50+
* @return the index as an int
51+
* @throws IndexOutOfBoundsException if the index is negative or exceeds
52+
* {@link Integer#MAX_VALUE}
53+
*/
54+
private int checkIndex(long index) {
55+
if (index < 0 || index > Integer.MAX_VALUE) {
56+
throw new IndexOutOfBoundsException(
57+
"Index out of bounds for SingleBuffer: " + index
58+
);
59+
}
60+
return (int) index;
61+
}
62+
63+
/** {@inheritDoc} */
64+
@Override
65+
public long capacity() {
66+
return buffer.capacity();
67+
}
68+
69+
/** {@inheritDoc} */
70+
@Override
71+
public long position() {
72+
return buffer.position();
73+
}
74+
75+
/** {@inheritDoc} */
76+
@Override
77+
public SingleBuffer position(long newPosition) {
78+
buffer.position(checkIndex(newPosition));
79+
return this;
80+
}
81+
82+
/** {@inheritDoc} */
83+
@Override
84+
public long limit() {
85+
return buffer.limit();
86+
}
87+
88+
/** {@inheritDoc} */
89+
@Override
90+
public SingleBuffer limit(long newLimit) {
91+
buffer.limit(checkIndex(newLimit));
92+
return this;
93+
}
94+
95+
/** {@inheritDoc} */
96+
@Override
97+
public byte get() {
98+
return buffer.get();
99+
}
100+
101+
/** {@inheritDoc} */
102+
@Override
103+
public SingleBuffer get(byte[] dst) {
104+
buffer.get(dst);
105+
return this;
106+
}
107+
108+
/** {@inheritDoc} */
109+
@Override
110+
public byte get(long index) {
111+
return buffer.get(checkIndex(index));
112+
}
113+
114+
/** {@inheritDoc} */
115+
@Override
116+
public double getDouble() {
117+
return buffer.getDouble();
118+
}
119+
120+
/** {@inheritDoc} */
121+
@Override
122+
public float getFloat() {
123+
return buffer.getFloat();
124+
}
125+
126+
/** {@inheritDoc} */
127+
@Override
128+
public SingleBuffer duplicate() {
129+
return new SingleBuffer(this.buffer.duplicate());
130+
}
131+
132+
/** {@inheritDoc} */
133+
@Override
134+
public long readFrom(FileChannel channel) throws IOException {
135+
return channel.read(buffer);
136+
}
137+
138+
/** {@inheritDoc} */
139+
@Override
140+
public String decode(CharsetDecoder decoder)
141+
throws CharacterCodingException {
142+
return decoder.decode(buffer).toString();
143+
}
144+
145+
/** {@inheritDoc} */
146+
@Override
147+
public SingleBuffer asReadOnlyBuffer() {
148+
return new SingleBuffer(buffer.asReadOnlyBuffer());
149+
}
150+
151+
/**
152+
* Wraps the given byte array in a new {@code SingleBuffer}.
153+
*
154+
* @param array the byte array to wrap
155+
* @return a new {@code SingleBuffer} backed by the array
156+
*/
157+
public static SingleBuffer wrap(byte[] array) {
158+
return new SingleBuffer(ByteBuffer.wrap(array));
159+
}
160+
161+
/**
162+
* Creates a read-only {@code SingleBuffer} by memory-mapping the given
163+
* {@link FileChannel}.
164+
*
165+
* @param channel the file channel to map
166+
* @return a new read-only {@code SingleBuffer}
167+
* @throws IOException if an I/O error occurs
168+
*/
169+
public static SingleBuffer mapFromChannel(FileChannel channel)
170+
throws IOException {
171+
ByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, channel.size());
172+
return new SingleBuffer(buffer.asReadOnlyBuffer());
173+
}
174+
}

0 commit comments

Comments
 (0)