|
18 | 18 | package org.apache.cassandra.io.util;
|
19 | 19 |
|
20 | 20 | import java.io.IOException;
|
| 21 | +import java.nio.ByteBuffer; |
21 | 22 | import java.nio.ByteOrder;
|
22 | 23 | import java.nio.FloatBuffer;
|
23 | 24 | import java.nio.IntBuffer;
|
@@ -92,165 +93,118 @@ public ByteOrder order()
|
92 | 93 | @Override
|
93 | 94 | public void read(float[] dest, int offset, int count) throws IOException
|
94 | 95 | {
|
95 |
| - var copied = 0; |
96 |
| - while (copied < count) |
| 96 | + for (int inBuffer = buffer.remaining() / Float.BYTES; |
| 97 | + inBuffer < count; |
| 98 | + inBuffer = buffer.remaining() / Float.BYTES) |
97 | 99 | {
|
98 |
| - var bh = bufferHolder; |
99 |
| - long position = getPosition(); |
100 |
| - |
101 |
| - FloatBuffer floatBuffer; |
102 |
| - if (bh.offset() == 0 && position % Float.BYTES == 0 && bh.order() == order) |
103 |
| - { |
104 |
| - // this is a separate code path because buffer() and asFloatBuffer() both allocate |
105 |
| - // new and relatively expensive xBuffer objects, so we want to avoid doing that |
106 |
| - // twice, where possible. If the BufferHandler has a different underlying |
107 |
| - // byte order, we duplicate first because there is not yet a way to configure |
108 |
| - // the buffer handler to use the correct byte order. |
109 |
| - floatBuffer = bh.floatBuffer(); |
110 |
| - floatBuffer.position(Ints.checkedCast(position / Float.BYTES)); |
111 |
| - } |
112 |
| - else |
| 100 | + if (inBuffer >= 1) |
113 | 101 | {
|
114 |
| - // bufferHolder offset is non-zero, and probably not aligned to Float.BYTES, so |
115 |
| - // set the position before converting to FloatBuffer. |
116 |
| - var bb = bh.buffer(); |
117 |
| - bb.order(order); |
118 |
| - bb.position(Ints.checkedCast(position - bh.offset())); |
119 |
| - floatBuffer = bb.asFloatBuffer(); |
| 102 | + // read as much as we can from the buffer |
| 103 | + readFloats(buffer, order, dest, offset, inBuffer); |
| 104 | + offset += inBuffer; |
| 105 | + count -= inBuffer; |
120 | 106 | }
|
121 | 107 |
|
122 |
| - var remaining = floatBuffer.remaining(); |
123 |
| - if (remaining == 0) |
| 108 | + if (buffer.remaining() > 0) |
124 | 109 | {
|
125 |
| - // slow path -- the next float bytes are across a buffer boundary (we never start a loop iteration with |
126 |
| - // the "current" buffer fully exhausted, so `remaining == 0` truly means "some bytes remains, but not |
127 |
| - // enough for a float"), so we read that float individually (which will read it byte by byte, |
128 |
| - // reBuffering as needed). After that we loop, which will switch back to the faster path for any |
129 |
| - // remaining floats in the newly reloaded buffer. |
130 |
| - dest[offset + copied] = readFloat(); |
131 |
| - seek(position + Float.BYTES); |
132 |
| - copied++; |
| 110 | + // read the buffer-spanning value using the slow path |
| 111 | + dest[offset++] = readFloat(); |
| 112 | + --count; |
133 | 113 | }
|
134 | 114 | else
|
135 |
| - { |
136 |
| - var elementsToRead = Math.min(remaining, count - copied); |
137 |
| - floatBuffer.get(dest, offset + copied, elementsToRead); |
138 |
| - seek(position + ((long) elementsToRead * Float.BYTES)); |
139 |
| - copied += elementsToRead; |
140 |
| - } |
| 115 | + reBuffer(); |
141 | 116 | }
|
| 117 | + |
| 118 | + readFloats(buffer, order, dest, offset, count); |
142 | 119 | }
|
143 | 120 |
|
144 | 121 | @Override
|
145 |
| - public void readFully(long[] dest) throws IOException { |
146 |
| - int copied = 0; |
147 |
| - while (copied < dest.length) |
148 |
| - { |
149 |
| - var bh = bufferHolder; |
150 |
| - long position = getPosition(); |
| 122 | + public void readFully(long[] dest) throws IOException |
| 123 | + { |
| 124 | + read(dest, 0, dest.length); |
| 125 | + } |
151 | 126 |
|
152 |
| - LongBuffer longBuffer; |
153 |
| - if (bh.offset() == 0 && position % Long.BYTES == 0 && bh.order() == order) |
154 |
| - { |
155 |
| - // this is a separate code path because buffer() and asLongBuffer() both allocate |
156 |
| - // new and relatively expensive xBuffer objects, so we want to avoid doing that |
157 |
| - // twice, where possible. If the BufferHandler has a different underlying |
158 |
| - // byte order, we duplicate first because there is not yet a way to configure |
159 |
| - // the buffer handler to use the correct byte order. |
160 |
| - longBuffer = bh.longBuffer(); |
161 |
| - longBuffer.position(Ints.checkedCast(position / Long.BYTES)); |
162 |
| - } |
163 |
| - else |
| 127 | + public void read(long[] dest, int offset, int count) throws IOException |
| 128 | + { |
| 129 | + for (int inBuffer = buffer.remaining() / Long.BYTES; |
| 130 | + inBuffer < count; |
| 131 | + inBuffer = buffer.remaining() / Long.BYTES) |
| 132 | + { |
| 133 | + if (inBuffer >= 1) |
164 | 134 | {
|
165 |
| - // offset is non-zero, and probably not aligned to Long.BYTES, so |
166 |
| - // set the position before converting to LongBuffer. |
167 |
| - var bb = bh.buffer(); |
168 |
| - bb.order(order); |
169 |
| - bb.position(Ints.checkedCast(position - bh.offset())); |
170 |
| - longBuffer = bb.asLongBuffer(); |
| 135 | + // read as much as we can from the buffer |
| 136 | + readLongs(buffer, order, dest, offset, inBuffer); |
| 137 | + offset += inBuffer; |
| 138 | + count -= inBuffer; |
171 | 139 | }
|
172 | 140 |
|
173 |
| - var remaining = longBuffer.remaining(); |
174 |
| - if (remaining == 0) |
| 141 | + if (buffer.remaining() > 0) |
175 | 142 | {
|
176 |
| - // slow path -- the next long bytes are across a buffer boundary (we never start a loop iteration with |
177 |
| - // the "current" buffer fully exhausted, so `remaining == 0` truly means "some bytes remains, but not |
178 |
| - // enough for a long"), so we read that long individually (which will read it byte by byte, |
179 |
| - // reBuffering as needed). After that we loop, which will switch back to the faster path for any |
180 |
| - // remaining longs in the newly reloaded buffer. |
181 |
| - dest[copied] = readLong(); |
182 |
| - seek(position + Long.BYTES); |
183 |
| - copied++; |
| 143 | + // read the buffer-spanning value using the slow path |
| 144 | + dest[offset++] = readLong(); |
| 145 | + --count; |
184 | 146 | }
|
185 | 147 | else
|
186 |
| - { |
187 |
| - var elementsToRead = Math.min(remaining, dest.length - copied); |
188 |
| - longBuffer.get(dest, copied, elementsToRead); |
189 |
| - seek(position + ((long) elementsToRead * Long.BYTES)); |
190 |
| - copied += elementsToRead; |
191 |
| - } |
| 148 | + reBuffer(); |
192 | 149 | }
|
| 150 | + |
| 151 | + readLongs(buffer, order, dest, offset, count); |
193 | 152 | }
|
194 | 153 |
|
195 |
| - /** |
196 |
| - * Read ints into an int[], starting at the current position. |
197 |
| - * |
198 |
| - * @param dest the array to read into |
199 |
| - * @param offset the offset in the array at which to start writing ints |
200 |
| - * @param count the number of ints to read |
201 |
| - * |
202 |
| - * Will change the buffer position. |
203 |
| - */ |
204 | 154 | @Override
|
205 | 155 | public void read(int[] dest, int offset, int count) throws IOException
|
206 | 156 | {
|
207 |
| - int copied = 0; |
208 |
| - while (copied < count) |
| 157 | + for (int inBuffer = buffer.remaining() / Integer.BYTES; |
| 158 | + inBuffer < count; |
| 159 | + inBuffer = buffer.remaining() / Integer.BYTES) |
209 | 160 | {
|
210 |
| - var bh = bufferHolder; |
211 |
| - long position = getPosition(); |
212 |
| - |
213 |
| - IntBuffer intBuffer; |
214 |
| - if (bh.offset() == 0 && position % Integer.BYTES == 0 && bh.order() == order) |
215 |
| - { |
216 |
| - // this is a separate code path because buffer() and asIntBuffer() both allocate |
217 |
| - // new and relatively expensive xBuffer objects, so we want to avoid doing that |
218 |
| - // twice, where possible. If the BufferHandler has a different underlying |
219 |
| - // byte order, we duplicate first because there is not yet a way to configure |
220 |
| - // the buffer handler to use the correct byte order. |
221 |
| - intBuffer = bh.intBuffer(); |
222 |
| - intBuffer.position(Ints.checkedCast(position / Integer.BYTES)); |
223 |
| - } |
224 |
| - else |
| 161 | + if (inBuffer >= 1) |
225 | 162 | {
|
226 |
| - // offset is non-zero, and probably not aligned to Integer.BYTES, so |
227 |
| - // set the position before converting to IntBuffer. |
228 |
| - var bb = bh.buffer(); |
229 |
| - bb.order(order); |
230 |
| - bb.position(Ints.checkedCast(position - bh.offset())); |
231 |
| - intBuffer = bb.asIntBuffer(); |
| 163 | + // read as much as we can from the buffer |
| 164 | + readInts(buffer, order, dest, offset, inBuffer); |
| 165 | + offset += inBuffer; |
| 166 | + count -= inBuffer; |
232 | 167 | }
|
233 | 168 |
|
234 |
| - var remaining = intBuffer.remaining(); |
235 |
| - if (remaining == 0) |
| 169 | + if (buffer.remaining() > 0) |
236 | 170 | {
|
237 |
| - // slow path -- the next int bytes are across a buffer boundary (we never start a loop iteration with |
238 |
| - // the "current" buffer fully exhausted, so `remaining == 0` truly means "some bytes remains, but not |
239 |
| - // enough for an int"), so we read that int individually (which will read it byte by byte, |
240 |
| - // reBuffering as needed). After that we loop, which will switch back to the faster path for any |
241 |
| - // remaining ints in the newly reloaded buffer. |
242 |
| - dest[offset + copied] = readInt(); |
243 |
| - seek(position + Integer.BYTES); |
244 |
| - copied++; |
| 171 | + // read the buffer-spanning value using the slow path |
| 172 | + dest[offset++] = readInt(); |
| 173 | + --count; |
245 | 174 | }
|
246 | 175 | else
|
247 |
| - { |
248 |
| - var elementsToRead = Math.min(remaining, count - copied); |
249 |
| - intBuffer.get(dest, offset + copied, elementsToRead); |
250 |
| - seek(position + ((long) elementsToRead * Integer.BYTES)); |
251 |
| - copied += elementsToRead; |
252 |
| - } |
| 176 | + reBuffer(); |
253 | 177 | }
|
| 178 | + |
| 179 | + readInts(buffer, order, dest, offset, count); |
| 180 | + } |
| 181 | + |
| 182 | + private static void readFloats(ByteBuffer buffer, ByteOrder order, float[] dest, int offset, int count) |
| 183 | + { |
| 184 | + FloatBuffer floatBuffer = updateBufferByteOrderIfNeeded(buffer, order).asFloatBuffer(); |
| 185 | + floatBuffer.get(dest, offset, count); |
| 186 | + buffer.position(buffer.position() + count * Float.BYTES); |
| 187 | + } |
| 188 | + |
| 189 | + private static void readLongs(ByteBuffer buffer, ByteOrder order, long[] dest, int offset, int count) |
| 190 | + { |
| 191 | + LongBuffer longBuffer = updateBufferByteOrderIfNeeded(buffer, order).asLongBuffer(); |
| 192 | + longBuffer.get(dest, offset, count); |
| 193 | + buffer.position(buffer.position() + count * Long.BYTES); |
| 194 | + } |
| 195 | + |
| 196 | + private static void readInts(ByteBuffer buffer, ByteOrder order, int[] dest, int offset, int count) |
| 197 | + { |
| 198 | + IntBuffer intBuffer = updateBufferByteOrderIfNeeded(buffer, order).asIntBuffer(); |
| 199 | + intBuffer.get(dest, offset, count); |
| 200 | + buffer.position(buffer.position() + count * Integer.BYTES); |
| 201 | + } |
| 202 | + |
| 203 | + private static ByteBuffer updateBufferByteOrderIfNeeded(ByteBuffer buffer, ByteOrder order) |
| 204 | + { |
| 205 | + return buffer.order() != order |
| 206 | + ? buffer.duplicate().order(order) |
| 207 | + : buffer; // Note: ?: rather than if to hit one-liner inlining path |
254 | 208 | }
|
255 | 209 |
|
256 | 210 | @Override
|
|
0 commit comments