1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.buffer.api.bytebuffer;
17
18 import io.netty5.buffer.api.AllocatorControl;
19 import io.netty5.buffer.api.Buffer;
20 import io.netty5.buffer.api.BufferAllocator;
21 import io.netty5.buffer.api.BufferClosedException;
22 import io.netty5.buffer.api.BufferReadOnlyException;
23 import io.netty5.buffer.api.ByteCursor;
24 import io.netty5.buffer.api.ComponentIterator;
25 import io.netty5.buffer.api.ComponentIterator.Next;
26 import io.netty5.buffer.api.Drop;
27 import io.netty5.buffer.api.Owned;
28 import io.netty5.buffer.api.ReadableComponent;
29 import io.netty5.buffer.api.ReadableComponentProcessor;
30 import io.netty5.buffer.api.WritableComponent;
31 import io.netty5.buffer.api.WritableComponentProcessor;
32 import io.netty5.buffer.api.internal.AdaptableBuffer;
33 import io.netty5.buffer.api.internal.NotReadOnlyReadableComponent;
34 import io.netty5.buffer.api.internal.SingleComponentIterator;
35 import io.netty5.buffer.api.internal.Statics;
36 import io.netty5.buffer.api.internal.Statics.UncheckedLoadByte;
37
38 import java.io.IOException;
39 import java.lang.ref.Reference;
40 import java.nio.ByteBuffer;
41 import java.nio.ByteOrder;
42 import java.nio.ReadOnlyBufferException;
43 import java.nio.channels.FileChannel;
44 import java.nio.channels.ReadableByteChannel;
45 import java.nio.channels.WritableByteChannel;
46
47 import static io.netty5.buffer.api.internal.Statics.MAX_BUFFER_SIZE;
48 import static io.netty5.buffer.api.internal.Statics.bbput;
49 import static io.netty5.buffer.api.internal.Statics.bbslice;
50 import static io.netty5.buffer.api.internal.Statics.bufferIsReadOnly;
51 import static io.netty5.buffer.api.internal.Statics.checkImplicitCapacity;
52 import static io.netty5.buffer.api.internal.Statics.checkLength;
53 import static io.netty5.buffer.api.internal.Statics.nativeAddressWithOffset;
54 import static io.netty5.buffer.api.internal.Statics.setMemory;
55 import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
56 import static io.netty5.util.internal.PlatformDependent.roundToPowerOfTwo;
57
58 final class NioBuffer extends AdaptableBuffer<NioBuffer>
59 implements ReadableComponent, WritableComponent, NotReadOnlyReadableComponent, ComponentIterator.Next {
60 private static final ByteBuffer CLOSED_BUFFER = ByteBuffer.allocate(0);
61
62 private ByteBuffer base;
63 private ByteBuffer rmem;
64 private ByteBuffer wmem;
65
66 private int roff;
67 private int woff;
68 private int implicitCapacityLimit;
69
70 NioBuffer(ByteBuffer base, ByteBuffer memory, AllocatorControl control, Drop<NioBuffer> drop) {
71 super(drop, control);
72 this.base = base;
73 rmem = memory;
74 wmem = memory;
75 implicitCapacityLimit = MAX_BUFFER_SIZE;
76 }
77
78
79
80
81 private NioBuffer(NioBuffer parent, Drop<NioBuffer> drop) {
82 super(drop, parent.control);
83 implicitCapacityLimit = parent.implicitCapacityLimit;
84 base = parent.base;
85 rmem = parent.rmem.duplicate();
86 wmem = CLOSED_BUFFER;
87 roff = parent.roff;
88 woff = parent.woff;
89 }
90
91 @Override
92 public String toString() {
93 return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rmem.capacity() + ']';
94 }
95
96 @Override
97 protected RuntimeException createResourceClosedException() {
98 return Statics.bufferIsClosed(this);
99 }
100
101 @Override
102 public int capacity() {
103 return rmem.capacity();
104 }
105
106 @Override
107 public int readerOffset() {
108 return roff;
109 }
110
111 @Override
112 public Buffer readerOffset(int offset) {
113 checkRead(offset, 0);
114 roff = offset;
115 return this;
116 }
117
118 @Override
119 public int writerOffset() {
120 return woff;
121 }
122
123 @Override
124 public Buffer writerOffset(int offset) {
125 if (readOnly()) {
126 throw bufferIsReadOnly(this);
127 }
128 checkWrite(offset, 0, false);
129 woff = offset;
130 return this;
131 }
132
133 @Override
134 public int readableBytes() {
135 return super.readableBytes();
136 }
137
138 @Override
139 public int writableBytes() {
140 return super.writableBytes();
141 }
142
143 @Override
144 public NioBuffer skipReadableBytes(int delta) {
145 return (NioBuffer) super.skipReadableBytes(delta);
146 }
147
148 @Override
149 public NioBuffer skipWritableBytes(int delta) {
150 return (NioBuffer) super.skipWritableBytes(delta);
151 }
152
153 @Override
154 public Buffer fill(byte value) {
155 int capacity = capacity();
156 checkSet(0, capacity);
157 if (rmem == CLOSED_BUFFER) {
158 throw bufferIsClosed();
159 }
160 final ByteBuffer wmem = this.wmem;
161 setMemory(wmem, capacity, value);
162 return this;
163 }
164
165 private long nativeAddress() {
166 return Statics.nativeAddressOfDirectByteBuffer(rmem);
167 }
168
169 @Override
170 public Buffer makeReadOnly() {
171 wmem = CLOSED_BUFFER;
172 return this;
173 }
174
175 @Override
176 public boolean readOnly() {
177 return wmem == CLOSED_BUFFER && rmem != CLOSED_BUFFER;
178 }
179
180 @Override
181 public boolean isDirect() {
182 return rmem.isDirect();
183 }
184
185 @Override
186 public Buffer implicitCapacityLimit(int limit) {
187 checkImplicitCapacity(limit, capacity());
188 implicitCapacityLimit = limit;
189 return this;
190 }
191
192 @Override
193 public int implicitCapacityLimit() {
194 return implicitCapacityLimit;
195 }
196
197 @Override
198 public Buffer copy(int offset, int length, boolean readOnly) {
199 checkLength(length);
200 checkGet(offset, length);
201 if (readOnly && readOnly()) {
202
203 NioBuffer copy = newConstChild();
204 if (offset > 0 || length < capacity()) {
205 copy.rmem = bbslice(copy.rmem, offset, length);
206 }
207 copy.roff = 0;
208 copy.woff = length;
209 return copy;
210 }
211 Buffer copy = control.getAllocator().allocate(length);
212 try {
213 copyInto(offset, copy, 0, length);
214 copy.writerOffset(length);
215 if (readOnly) {
216 copy.makeReadOnly();
217 }
218 return copy;
219 } catch (Throwable e) {
220 copy.close();
221 throw e;
222 }
223 }
224
225 @Override
226 public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
227 copyInto(srcPos, ByteBuffer.wrap(dest), destPos, length);
228 }
229
230 @Override
231 public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
232 if (rmem == CLOSED_BUFFER) {
233 throw bufferIsClosed();
234 }
235 if (srcPos < 0) {
236 throw new IndexOutOfBoundsException("The srcPos cannot be negative: " + srcPos + '.');
237 }
238 if (destPos < 0) {
239 throw new IndexOutOfBoundsException("The destination position cannot be negative: " + destPos);
240 }
241 checkLength(length);
242 if (capacity() < srcPos + length) {
243 throw new IndexOutOfBoundsException("The srcPos + length is beyond the end of the buffer: " +
244 "srcPos = " + srcPos + ", length = " + length + '.');
245 }
246 if (dest.capacity() < destPos + length) {
247 throw new IndexOutOfBoundsException("The destPos + length is beyond the end of the buffer: " +
248 "destPos = " + destPos + ", length = " + length + '.');
249 }
250 if (dest.hasArray() && hasReadableArray()) {
251 final byte[] srcArray = rmem.array();
252 final int srcStart = rmem.arrayOffset() + srcPos;
253 final byte[] dstArray = dest.array();
254 final int dstStart = dest.arrayOffset() + destPos;
255 System.arraycopy(srcArray, srcStart, dstArray, dstStart, length);
256 return;
257 }
258 dest = dest.duplicate().clear();
259 bbput(dest, destPos, rmem, srcPos, length);
260 }
261
262 @Override
263 public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
264 if (!isAccessible()) {
265 throw bufferIsClosed();
266 }
267 if (dest.readOnly()) {
268 throw bufferIsReadOnly(dest);
269 }
270 if (dest instanceof NioBuffer) {
271 var nb = (NioBuffer) dest;
272 nb.checkSet(destPos, length);
273 copyInto(srcPos, nb.wmem, destPos, length);
274 return;
275 }
276
277 Statics.copyToViaReverseLoop(this, srcPos, dest, destPos, length);
278 }
279
280 @Override
281 public int transferTo(WritableByteChannel channel, int length) throws IOException {
282 if (!isAccessible()) {
283 throw bufferIsClosed();
284 }
285 length = Math.min(readableBytes(), length);
286 if (length == 0) {
287 return 0;
288 }
289 checkGet(readerOffset(), length);
290 int bytesWritten = channel.write(readableBuffer().limit(length));
291 skipReadableBytes(bytesWritten);
292 return bytesWritten;
293 }
294
295 @Override
296 public int transferFrom(FileChannel channel, long position, int length) throws IOException {
297 checkPositiveOrZero(position, "position");
298 checkPositiveOrZero(length, "length");
299 if (!isAccessible()) {
300 throw bufferIsClosed();
301 }
302 if (readOnly()) {
303 throw bufferIsReadOnly(this);
304 }
305 length = Math.min(writableBytes(), length);
306 if (length == 0) {
307 return 0;
308 }
309 checkSet(writerOffset(), length);
310 int bytesRead = channel.read(writableBuffer().limit(length), position);
311 if (bytesRead > 0) {
312 skipWritableBytes(bytesRead);
313 }
314 return bytesRead;
315 }
316
317 @Override
318 public int transferFrom(ReadableByteChannel channel, int length) throws IOException {
319 if (!isAccessible()) {
320 throw bufferIsClosed();
321 }
322 if (readOnly()) {
323 throw bufferIsReadOnly(this);
324 }
325 length = Math.min(writableBytes(), length);
326 if (length == 0) {
327 return 0;
328 }
329 checkSet(writerOffset(), length);
330 int bytesRead = channel.read(writableBuffer().limit(length));
331 if (bytesRead != -1) {
332 skipWritableBytes(bytesRead);
333 }
334 return bytesRead;
335 }
336
337 @Override
338 public int bytesBefore(byte needle) {
339
340
341 if (!isAccessible()) {
342 throw bufferIsClosed();
343 }
344 int offset = roff;
345 final int length = woff - roff;
346 final int end = woff;
347
348 if (length > 7) {
349 final long pattern = (needle & 0xFFL) * 0x101010101010101L;
350 for (final int longEnd = offset + (length >>> 3) * Long.BYTES;
351 offset < longEnd;
352 offset += Long.BYTES) {
353 final long word = rmem.getLong(offset);
354
355 long input = word ^ pattern;
356 long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;
357 tmp = ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);
358 final int binaryPosition = Long.numberOfLeadingZeros(tmp);
359
360 int index = binaryPosition >>> 3;
361 if (index < Long.BYTES) {
362 return offset + index - roff;
363 }
364 }
365 }
366 for (; offset < end; offset++) {
367 if (rmem.get(offset) == needle) {
368 return offset - roff;
369 }
370 }
371
372 return -1;
373 }
374
375 @Override
376 public int bytesBefore(Buffer needle) {
377 UncheckedLoadByte uncheckedLoadByte = NioBuffer::uncheckedLoadByte;
378 return Statics.bytesBefore(this, uncheckedLoadByte,
379 needle, needle instanceof NioBuffer ? uncheckedLoadByte : null);
380 }
381
382
383
384
385 private static byte uncheckedLoadByte(Buffer buffer, int offset) {
386 return ((NioBuffer) buffer).rmem.get(offset);
387 }
388
389 @Override
390 public ByteCursor openCursor() {
391 return openCursor(readerOffset(), readableBytes());
392 }
393
394 @Override
395 public ByteCursor openCursor(int fromOffset, int length) {
396 if (rmem == CLOSED_BUFFER) {
397 throw bufferIsClosed();
398 }
399 if (fromOffset < 0) {
400 throw new IndexOutOfBoundsException("The fromOffset cannot be negative: " + fromOffset + '.');
401 }
402 checkLength(length);
403 if (capacity() < fromOffset + length) {
404 throw new IndexOutOfBoundsException("The fromOffset + length is beyond the end of the buffer: " +
405 "fromOffset = " + fromOffset + ", length = " + length + '.');
406 }
407 return new ForwardNioByteCursor(rmem, fromOffset, length);
408 }
409
410 @Override
411 public ByteCursor openReverseCursor(int fromOffset, int length) {
412 if (rmem == CLOSED_BUFFER) {
413 throw bufferIsClosed();
414 }
415 if (fromOffset < 0) {
416 throw new IndexOutOfBoundsException("The fromOffset cannot be negative: " + fromOffset + '.');
417 }
418 checkLength(length);
419 if (capacity() <= fromOffset) {
420 throw new IndexOutOfBoundsException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
421 }
422 if (fromOffset - length < -1) {
423 throw new IndexOutOfBoundsException("The fromOffset - length would underflow the buffer: " +
424 "fromOffset = " + fromOffset + ", length = " + length + '.');
425 }
426 return new ReverseNioByteCursor(rmem, fromOffset, length);
427 }
428
429 @Override
430 public Buffer ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
431 if (!isAccessible()) {
432 throw bufferIsClosed();
433 }
434 if (!isOwned()) {
435 throw attachTrace(new IllegalStateException(
436 "Buffer is not owned. Only owned buffers can call ensureWritable."));
437 }
438 if (size < 0) {
439 throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
440 }
441 if (minimumGrowth < 0) {
442 throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
443 }
444 if (rmem != wmem) {
445 throw bufferIsReadOnly(this);
446 }
447 if (writableBytes() >= size) {
448
449 return this;
450 }
451
452 if (allowCompaction && writableBytes() + readerOffset() >= size) {
453
454 return compact();
455 }
456
457
458 long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
459 Statics.assertValidBufferSize(newSize);
460 NioBuffer buffer = (NioBuffer) control.getAllocator().allocate((int) newSize);
461
462
463 copyInto(0, buffer, 0, capacity());
464
465
466 Drop<NioBuffer> drop = buffer.unsafeGetDrop();
467 disconnectDrop(drop);
468 attachNewBuffer(buffer, drop);
469 return this;
470 }
471
472 private void disconnectDrop(Drop<NioBuffer> newDrop) {
473 var drop = (Drop<NioBuffer>) unsafeGetDrop();
474 int roff = this.roff;
475 int woff = this.woff;
476 drop.drop(this);
477 unsafeSetDrop(newDrop);
478 this.roff = roff;
479 this.woff = woff;
480 }
481
482 private void attachNewBuffer(NioBuffer buffer, Drop<NioBuffer> drop) {
483 base = buffer.base;
484 rmem = buffer.rmem;
485 wmem = buffer.wmem;
486 drop.attach(this);
487 }
488
489 @Override
490 public Buffer split(int splitOffset) {
491 if (splitOffset < 0) {
492 throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
493 }
494 if (capacity() < splitOffset) {
495 throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
496 "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
497 }
498 if (!isAccessible()) {
499 throw bufferIsClosed();
500 }
501 if (!isOwned()) {
502 throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned."));
503 }
504 var drop = unsafeGetDrop().fork();
505 var splitByteBuffer = bbslice(rmem, 0, splitOffset);
506 var splitBuffer = new NioBuffer(base, splitByteBuffer, control, drop);
507 drop.attach(splitBuffer);
508 splitBuffer.woff = Math.min(woff, splitOffset);
509 splitBuffer.roff = Math.min(roff, splitOffset);
510 boolean readOnly = readOnly();
511 if (readOnly) {
512 splitBuffer.makeReadOnly();
513 }
514
515 rmem = bbslice(rmem, splitOffset, rmem.capacity() - splitOffset);
516 if (!readOnly) {
517 wmem = rmem;
518 }
519 woff = Math.max(woff, splitOffset) - splitOffset;
520 roff = Math.max(roff, splitOffset) - splitOffset;
521 return splitBuffer;
522 }
523
524 @Override
525 public Buffer compact() {
526 if (!isAccessible()) {
527 throw bufferIsClosed();
528 }
529 if (!isOwned()) {
530 throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact."));
531 }
532 if (readOnly()) {
533 throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only.");
534 }
535 if (roff == 0) {
536 return this;
537 }
538 rmem.limit(woff).position(roff).compact().clear();
539 woff -= roff;
540 roff = 0;
541 return this;
542 }
543
544 @Override
545 public int countComponents() {
546 return 1;
547 }
548
549 @Override
550 public int countReadableComponents() {
551 return readableBytes() > 0? 1 : 0;
552 }
553
554 @Override
555 public int countWritableComponents() {
556 return writableBytes() > 0? 1 : 0;
557 }
558
559
560 @Override
561 public boolean hasReadableArray() {
562 return rmem.hasArray();
563 }
564
565 @Override
566 public byte[] readableArray() {
567 return rmem.array();
568 }
569
570 @Override
571 public int readableArrayOffset() {
572 return rmem.arrayOffset() + roff;
573 }
574
575 @Override
576 public int readableArrayLength() {
577 return woff - roff;
578 }
579
580 @Override
581 public long readableNativeAddress() {
582 return nativeAddressWithOffset(nativeAddress(), roff);
583 }
584
585 @Override
586 public ByteBuffer readableBuffer() {
587 return bbslice(rmem.asReadOnlyBuffer(), readerOffset(), readableBytes());
588 }
589
590 @Override
591 public ByteBuffer mutableReadableBuffer() {
592 return bbslice(rmem, readerOffset(), readableBytes());
593 }
594
595 @Override
596 public boolean hasWritableArray() {
597 return wmem.hasArray();
598 }
599
600 @Override
601 public byte[] writableArray() {
602 return wmem.array();
603 }
604
605 @Override
606 public int writableArrayOffset() {
607 return wmem.arrayOffset() + woff;
608 }
609
610 @Override
611 public int writableArrayLength() {
612 return capacity() - woff;
613 }
614
615 @Override
616 public long writableNativeAddress() {
617 return nativeAddressWithOffset(nativeAddress(), woff);
618 }
619
620 @Override
621 public ByteBuffer writableBuffer() {
622 return bbslice(wmem, writerOffset(), writableBytes());
623 }
624
625 @Override
626 public <N extends Next> N next() {
627 return null;
628 }
629
630
631 @Override
632 public <E extends Exception> int forEachReadable(int initialIndex, ReadableComponentProcessor<E> processor)
633 throws E {
634 if (!isAccessible()) {
635 throw bufferIsClosed();
636 }
637 int readableBytes = readableBytes();
638 if (readableBytes == 0) {
639 return 0;
640 }
641 checkRead(readerOffset(), readableBytes);
642 try {
643 return processor.process(initialIndex, this)? 1 : -1;
644 } finally {
645 Reference.reachabilityFence(this);
646 }
647 }
648
649 @Override
650 public <T extends ReadableComponent & Next> ComponentIterator<T> forEachReadable() {
651 return new SingleComponentIterator<>(acquire(), readableBytes() > 0 ? this : null);
652 }
653
654 @Override
655 public <E extends Exception> int forEachWritable(int initialIndex, WritableComponentProcessor<E> processor)
656 throws E {
657 if (!isAccessible()) {
658 throw bufferIsClosed();
659 }
660 int writableBytes = writableBytes();
661 if (writableBytes == 0) {
662 return 0;
663 }
664 checkWrite(writerOffset(), writableBytes, false);
665 try {
666 return processor.process(initialIndex, this)? 1 : -1;
667 } finally {
668 Reference.reachabilityFence(this);
669 }
670 }
671
672 @Override
673 public <T extends WritableComponent & Next> ComponentIterator<T> forEachWritable() {
674 checkWrite(writerOffset(), writableBytes(), false);
675 return new SingleComponentIterator<>(acquire(), writableBytes() > 0 ? this : null);
676 }
677
678
679 @Override
680 public byte readByte() {
681 checkRead(roff, Byte.BYTES);
682 var value = rmem.get(roff);
683 roff += Byte.BYTES;
684 return value;
685 }
686
687 @Override
688 public byte getByte(int roff) {
689 checkGet(roff, Byte.BYTES);
690 return rmem.get(roff);
691 }
692
693 @Override
694 public int readUnsignedByte() {
695 return readByte() & 0xFF;
696 }
697
698 @Override
699 public int getUnsignedByte(int roff) {
700 return getByte(roff) & 0xFF;
701 }
702
703 @Override
704 public Buffer writeByte(byte value) {
705 checkWrite(woff, Byte.BYTES, true);
706 try {
707 wmem.put(woff, value);
708 woff += Byte.BYTES;
709 return this;
710 } catch (IndexOutOfBoundsException e) {
711 throw checkWriteState(e, woff, Byte.BYTES);
712 } catch (ReadOnlyBufferException e) {
713 throw bufferIsReadOnly(this);
714 }
715 }
716
717 @Override
718 public Buffer setByte(int woff, byte value) {
719 try {
720 wmem.put(woff, value);
721 return this;
722 } catch (IndexOutOfBoundsException e) {
723 throw checkWriteState(e, woff, Byte.BYTES);
724 } catch (ReadOnlyBufferException e) {
725 throw bufferIsReadOnly(this);
726 }
727 }
728
729 @Override
730 public Buffer writeUnsignedByte(int value) {
731 checkWrite(woff, Byte.BYTES, true);
732 try {
733 wmem.put(woff, (byte) (value & 0xFF));
734 woff += Byte.BYTES;
735 return this;
736 } catch (IndexOutOfBoundsException e) {
737 throw checkWriteState(e, woff, Byte.BYTES);
738 } catch (ReadOnlyBufferException e) {
739 throw bufferIsReadOnly(this);
740 }
741 }
742
743 @Override
744 public Buffer setUnsignedByte(int woff, int value) {
745 try {
746 wmem.put(woff, (byte) (value & 0xFF));
747 return this;
748 } catch (IndexOutOfBoundsException e) {
749 throw checkWriteState(e, woff, Byte.BYTES);
750 } catch (ReadOnlyBufferException e) {
751 throw bufferIsReadOnly(this);
752 }
753 }
754
755 @Override
756 public char readChar() {
757 checkRead(roff, Character.BYTES);
758 var value = rmem.getChar(roff);
759 roff += Character.BYTES;
760 return value;
761 }
762
763 @Override
764 public char getChar(int roff) {
765 checkGet(roff, Character.BYTES);
766 return rmem.getChar(roff);
767 }
768
769 @Override
770 public Buffer writeChar(char value) {
771 checkWrite(woff, Character.BYTES, true);
772 try {
773 wmem.putChar(woff, value);
774 woff += Character.BYTES;
775 return this;
776 } catch (IndexOutOfBoundsException e) {
777 throw checkWriteState(e, woff, Character.BYTES);
778 } catch (ReadOnlyBufferException e) {
779 throw bufferIsReadOnly(this);
780 }
781 }
782
783 @Override
784 public Buffer setChar(int woff, char value) {
785 try {
786 wmem.putChar(woff, value);
787 return this;
788 } catch (IndexOutOfBoundsException e) {
789 throw checkWriteState(e, woff, Character.BYTES);
790 } catch (ReadOnlyBufferException e) {
791 throw bufferIsReadOnly(this);
792 }
793 }
794
795 @Override
796 public short readShort() {
797 checkRead(roff, Short.BYTES);
798 var value = rmem.getShort(roff);
799 roff += Short.BYTES;
800 return value;
801 }
802
803 @Override
804 public short getShort(int roff) {
805 checkGet(roff, Short.BYTES);
806 return rmem.getShort(roff);
807 }
808
809 @Override
810 public int readUnsignedShort() {
811 checkRead(roff, Short.BYTES);
812 var value = rmem.getShort(roff) & 0xFFFF;
813 roff += Short.BYTES;
814 return value;
815 }
816
817 @Override
818 public int getUnsignedShort(int roff) {
819 checkGet(roff, Short.BYTES);
820 return rmem.getShort(roff) & 0xFFFF;
821 }
822
823 @Override
824 public Buffer writeShort(short value) {
825 checkWrite(woff, Short.BYTES, true);
826 try {
827 wmem.putShort(woff, value);
828 woff += Short.BYTES;
829 return this;
830 } catch (IndexOutOfBoundsException e) {
831 throw checkWriteState(e, woff, Short.BYTES);
832 } catch (ReadOnlyBufferException e) {
833 throw bufferIsReadOnly(this);
834 }
835 }
836
837 @Override
838 public Buffer setShort(int woff, short value) {
839 try {
840 wmem.putShort(woff, value);
841 return this;
842 } catch (IndexOutOfBoundsException e) {
843 throw checkWriteState(e, woff, Short.BYTES);
844 } catch (ReadOnlyBufferException e) {
845 throw bufferIsReadOnly(this);
846 }
847 }
848
849 @Override
850 public Buffer writeUnsignedShort(int value) {
851 checkWrite(woff, Short.BYTES, true);
852 try {
853 wmem.putShort(woff, (short) (value & 0xFFFF));
854 woff += Short.BYTES;
855 return this;
856 } catch (IndexOutOfBoundsException e) {
857 throw checkWriteState(e, woff, Short.BYTES);
858 } catch (ReadOnlyBufferException e) {
859 throw bufferIsReadOnly(this);
860 }
861 }
862
863 @Override
864 public Buffer setUnsignedShort(int woff, int value) {
865 try {
866 wmem.putShort(woff, (short) (value & 0xFFFF));
867 return this;
868 } catch (IndexOutOfBoundsException e) {
869 throw checkWriteState(e, woff, Short.BYTES);
870 } catch (ReadOnlyBufferException e) {
871 throw bufferIsReadOnly(this);
872 }
873 }
874
875 @Override
876 public int readMedium() {
877 checkRead(roff, 3);
878 int value = rmem.get(roff) << 16 | (rmem.get(roff + 1) & 0xFF) << 8 | rmem.get(roff + 2) & 0xFF;
879 roff += 3;
880 return value;
881 }
882
883 @Override
884 public int getMedium(int roff) {
885 checkGet(roff, 3);
886 return rmem.get(roff) << 16 | (rmem.get(roff + 1) & 0xFF) << 8 | rmem.get(roff + 2) & 0xFF;
887 }
888
889 @Override
890 public int readUnsignedMedium() {
891 checkRead(roff, 3);
892 int value = (rmem.get(roff) << 16 | (rmem.get(roff + 1) & 0xFF) << 8 | rmem.get(roff + 2) & 0xFF) & 0xFFFFFF;
893 roff += 3;
894 return value;
895 }
896
897 @Override
898 public int getUnsignedMedium(int roff) {
899 checkGet(roff, 3);
900 return (rmem.get(roff) << 16 | (rmem.get(roff + 1) & 0xFF) << 8 | rmem.get(roff + 2) & 0xFF) & 0xFFFFFF;
901 }
902
903 @Override
904 public Buffer writeMedium(int value) {
905 checkWrite(woff, 3, true);
906 wmem.put(woff, (byte) (value >> 16));
907 wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
908 wmem.put(woff + 2, (byte) (value & 0xFF));
909 woff += 3;
910 return this;
911 }
912
913 @Override
914 public Buffer setMedium(int woff, int value) {
915 checkSet(woff, 3);
916 wmem.put(woff, (byte) (value >> 16));
917 wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
918 wmem.put(woff + 2, (byte) (value & 0xFF));
919 return this;
920 }
921
922 @Override
923 public Buffer writeUnsignedMedium(int value) {
924 checkWrite(woff, 3, true);
925 wmem.put(woff, (byte) (value >> 16));
926 wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
927 wmem.put(woff + 2, (byte) (value & 0xFF));
928 woff += 3;
929 return this;
930 }
931
932 @Override
933 public Buffer setUnsignedMedium(int woff, int value) {
934 checkSet(woff, 3);
935 wmem.put(woff, (byte) (value >> 16));
936 wmem.put(woff + 1, (byte) (value >> 8 & 0xFF));
937 wmem.put(woff + 2, (byte) (value & 0xFF));
938 return this;
939 }
940
941 @Override
942 public int readInt() {
943 checkRead(roff, Integer.BYTES);
944 var value = rmem.getInt(roff);
945 roff += Integer.BYTES;
946 return value;
947 }
948
949 @Override
950 public int getInt(int roff) {
951 checkGet(roff, Integer.BYTES);
952 return rmem.getInt(roff);
953 }
954
955 @Override
956 public long readUnsignedInt() {
957 checkRead(roff, Integer.BYTES);
958 var value = rmem.getInt(roff) & 0xFFFFFFFFL;
959 roff += Integer.BYTES;
960 return value;
961 }
962
963 @Override
964 public long getUnsignedInt(int roff) {
965 checkGet(roff, Integer.BYTES);
966 return rmem.getInt(roff) & 0xFFFFFFFFL;
967 }
968
969 @Override
970 public Buffer writeInt(int value) {
971 checkWrite(woff, Integer.BYTES, true);
972 try {
973 wmem.putInt(woff, value);
974 woff += Integer.BYTES;
975 return this;
976 } catch (IndexOutOfBoundsException e) {
977 throw checkWriteState(e, woff, Integer.BYTES);
978 } catch (ReadOnlyBufferException e) {
979 throw bufferIsReadOnly(this);
980 }
981 }
982
983 @Override
984 public Buffer setInt(int woff, int value) {
985 try {
986 wmem.putInt(woff, value);
987 return this;
988 } catch (IndexOutOfBoundsException e) {
989 throw checkWriteState(e, this.woff, Integer.BYTES);
990 } catch (ReadOnlyBufferException e) {
991 throw bufferIsReadOnly(this);
992 }
993 }
994
995 @Override
996 public Buffer writeUnsignedInt(long value) {
997 checkWrite(woff, Integer.BYTES, true);
998 try {
999 wmem.putInt(woff, (int) (value & 0xFFFFFFFFL));
1000 woff += Integer.BYTES;
1001 return this;
1002 } catch (IndexOutOfBoundsException e) {
1003 throw checkWriteState(e, woff, Integer.BYTES);
1004 } catch (ReadOnlyBufferException e) {
1005 throw bufferIsReadOnly(this);
1006 }
1007 }
1008
1009 @Override
1010 public Buffer setUnsignedInt(int woff, long value) {
1011 try {
1012 wmem.putInt(woff, (int) (value & 0xFFFFFFFFL));
1013 return this;
1014 } catch (IndexOutOfBoundsException e) {
1015 throw checkWriteState(e, this.woff, Integer.BYTES);
1016 } catch (ReadOnlyBufferException e) {
1017 throw bufferIsReadOnly(this);
1018 }
1019 }
1020
1021 @Override
1022 public float readFloat() {
1023 checkRead(roff, Float.BYTES);
1024 var value = rmem.getFloat(roff);
1025 roff += Float.BYTES;
1026 return value;
1027 }
1028
1029 @Override
1030 public float getFloat(int roff) {
1031 checkGet(roff, Float.BYTES);
1032 return rmem.getFloat(roff);
1033 }
1034
1035 @Override
1036 public Buffer writeFloat(float value) {
1037 checkWrite(woff, Float.BYTES, true);
1038 try {
1039 wmem.putFloat(woff, value);
1040 woff += Float.BYTES;
1041 return this;
1042 } catch (IndexOutOfBoundsException e) {
1043 throw checkWriteState(e, woff, Float.BYTES);
1044 } catch (ReadOnlyBufferException e) {
1045 throw bufferIsReadOnly(this);
1046 }
1047 }
1048
1049 @Override
1050 public Buffer setFloat(int woff, float value) {
1051 try {
1052 wmem.putFloat(woff, value);
1053 return this;
1054 } catch (IndexOutOfBoundsException e) {
1055 throw checkWriteState(e, woff, Float.BYTES);
1056 } catch (ReadOnlyBufferException e) {
1057 throw bufferIsReadOnly(this);
1058 }
1059 }
1060
1061 @Override
1062 public long readLong() {
1063 checkRead(roff, Long.BYTES);
1064 var value = rmem.getLong(roff);
1065 roff += Long.BYTES;
1066 return value;
1067 }
1068
1069 @Override
1070 public long getLong(int roff) {
1071 checkGet(roff, Long.BYTES);
1072 return rmem.getLong(roff);
1073 }
1074
1075 @Override
1076 public Buffer writeLong(long value) {
1077 checkWrite(woff, Long.BYTES, true);
1078 try {
1079 wmem.putLong(woff, value);
1080 woff += Long.BYTES;
1081 return this;
1082 } catch (IndexOutOfBoundsException e) {
1083 throw checkWriteState(e, woff, Long.BYTES);
1084 } catch (ReadOnlyBufferException e) {
1085 throw bufferIsReadOnly(this);
1086 }
1087 }
1088
1089 @Override
1090 public Buffer setLong(int woff, long value) {
1091 try {
1092 wmem.putLong(woff, value);
1093 return this;
1094 } catch (IndexOutOfBoundsException e) {
1095 throw checkWriteState(e, woff, Long.BYTES);
1096 } catch (ReadOnlyBufferException e) {
1097 throw bufferIsReadOnly(this);
1098 }
1099 }
1100
1101 @Override
1102 public double readDouble() {
1103 checkRead(roff, Double.BYTES);
1104 var value = rmem.getDouble(roff);
1105 roff += Double.BYTES;
1106 return value;
1107 }
1108
1109 @Override
1110 public double getDouble(int roff) {
1111 checkGet(roff, Double.BYTES);
1112 return rmem.getDouble(roff);
1113 }
1114
1115 @Override
1116 public Buffer writeDouble(double value) {
1117 checkWrite(woff, Double.BYTES, true);
1118 try {
1119 wmem.putDouble(woff, value);
1120 woff += Double.BYTES;
1121 return this;
1122 } catch (IndexOutOfBoundsException e) {
1123 throw checkWriteState(e, woff, Double.BYTES);
1124 } catch (ReadOnlyBufferException e) {
1125 throw bufferIsReadOnly(this);
1126 }
1127 }
1128
1129 @Override
1130 public Buffer setDouble(int woff, double value) {
1131 try {
1132 wmem.putDouble(woff, value);
1133 return this;
1134 } catch (IndexOutOfBoundsException e) {
1135 throw checkWriteState(e, woff, Double.BYTES);
1136 } catch (ReadOnlyBufferException e) {
1137 throw bufferIsReadOnly(this);
1138 }
1139 }
1140
1141
1142 @Override
1143 protected Owned<NioBuffer> prepareSend() {
1144 int roff = this.roff;
1145 int woff = this.woff;
1146 boolean readOnly = readOnly();
1147 int implicitCapacityLimit = this.implicitCapacityLimit;
1148 ByteBuffer base = this.base;
1149 ByteBuffer rmem = this.rmem;
1150 return drop -> {
1151 NioBuffer copy = new NioBuffer(base, rmem, control, drop);
1152 copy.roff = roff;
1153 copy.woff = woff;
1154 copy.implicitCapacityLimit = implicitCapacityLimit;
1155 if (readOnly) {
1156 copy.makeReadOnly();
1157 }
1158 return copy;
1159 };
1160 }
1161
1162 @Override
1163 protected void makeInaccessible() {
1164 base = CLOSED_BUFFER;
1165 rmem = CLOSED_BUFFER;
1166 wmem = CLOSED_BUFFER;
1167 roff = 0;
1168 woff = 0;
1169 }
1170
1171 private void checkRead(int index, int size) {
1172 if (index < 0 | woff < index + size) {
1173 throw readAccessCheckException(index, size);
1174 }
1175 }
1176
1177 private void checkGet(int index, int size) {
1178 if (index < 0 | capacity() < index + size) {
1179 throw readAccessCheckException(index, size);
1180 }
1181 }
1182
1183 private void checkWrite(int index, int size, boolean mayExpand) {
1184 if (index < roff | wmem.capacity() < index + size) {
1185 handleWriteAccessBoundsFailure(index, size, mayExpand);
1186 }
1187 }
1188
1189 private void checkSet(int index, int size) {
1190 if (index < 0 | wmem.capacity() < index + size) {
1191 handleWriteAccessBoundsFailure(index, size, false);
1192 }
1193 }
1194
1195 private RuntimeException checkWriteState(IndexOutOfBoundsException ioobe, int offset, int size) {
1196 if (rmem == CLOSED_BUFFER) {
1197 return bufferIsClosed();
1198 }
1199 if (wmem != rmem) {
1200 return bufferIsReadOnly(this);
1201 }
1202
1203 IndexOutOfBoundsException exception = outOfBounds(offset, size);
1204 exception.addSuppressed(ioobe);
1205 return exception;
1206 }
1207
1208 private RuntimeException readAccessCheckException(int index, int size) {
1209 if (rmem == CLOSED_BUFFER) {
1210 return bufferIsClosed();
1211 }
1212 return outOfBounds(index, size);
1213 }
1214
1215 private void handleWriteAccessBoundsFailure(int index, int size, boolean mayExpand) {
1216 if (rmem == CLOSED_BUFFER) {
1217 throw bufferIsClosed();
1218 }
1219 if (wmem != rmem) {
1220 throw bufferIsReadOnly(this);
1221 }
1222 int capacity = capacity();
1223 if (mayExpand && index >= 0 && index <= capacity && woff + size <= implicitCapacityLimit && isOwned()) {
1224
1225 int minimumGrowth = Math.min(
1226 Math.max(roundToPowerOfTwo(capacity * 2), size),
1227 implicitCapacityLimit) - capacity;
1228 ensureWritable(size, minimumGrowth, false);
1229 checkSet(index, size);
1230 return;
1231 }
1232 throw outOfBounds(index, size);
1233 }
1234
1235 private BufferClosedException bufferIsClosed() {
1236 return attachTrace(Statics.bufferIsClosed(this));
1237 }
1238
1239 private IndexOutOfBoundsException outOfBounds(int index, int size) {
1240 return new IndexOutOfBoundsException(
1241 "Access at index " + index + " of size " + size + " is out of bounds: " +
1242 "[read 0 to " + woff + ", write 0 to " + rmem.capacity() + "].");
1243 }
1244
1245 ByteBuffer recoverable() {
1246 return base;
1247 }
1248
1249 NioBuffer newConstChild() {
1250 assert readOnly();
1251 Drop<NioBuffer> drop = unsafeGetDrop().fork();
1252 NioBuffer child = new NioBuffer(this, drop);
1253 drop.attach(child);
1254 return child;
1255 }
1256
1257 private static final class ForwardNioByteCursor implements ByteCursor {
1258
1259 final ByteBuffer buffer;
1260 int index;
1261 final int end;
1262 byte byteValue;
1263
1264 ForwardNioByteCursor(ByteBuffer rmem, int fromOffset, int length) {
1265 buffer = rmem.duplicate().order(ByteOrder.BIG_ENDIAN);
1266 index = fromOffset;
1267 end = index + length;
1268 byteValue = -1;
1269 }
1270
1271 @Override
1272 public boolean readByte() {
1273 if (index < end) {
1274 byteValue = buffer.get(index);
1275 index++;
1276 return true;
1277 }
1278 return false;
1279 }
1280
1281 @Override
1282 public byte getByte() {
1283 return byteValue;
1284 }
1285
1286 @Override
1287 public int currentOffset() {
1288 return index;
1289 }
1290
1291 @Override
1292 public int bytesLeft() {
1293 return end - index;
1294 }
1295 }
1296
1297 private static final class ReverseNioByteCursor implements ByteCursor {
1298 final ByteBuffer buffer;
1299 int index;
1300 final int end;
1301 byte byteValue;
1302
1303 ReverseNioByteCursor(ByteBuffer rmem, int fromOffset, int length) {
1304 buffer = rmem.duplicate().order(ByteOrder.LITTLE_ENDIAN);
1305 index = fromOffset;
1306 end = index - length;
1307 byteValue = -1;
1308 }
1309
1310 @Override
1311 public boolean readByte() {
1312 if (index > end) {
1313 byteValue = buffer.get(index);
1314 index--;
1315 return true;
1316 }
1317 return false;
1318 }
1319
1320 @Override
1321 public byte getByte() {
1322 return byteValue;
1323 }
1324
1325 @Override
1326 public int currentOffset() {
1327 return index;
1328 }
1329
1330 @Override
1331 public int bytesLeft() {
1332 return index - end;
1333 }
1334 }
1335 }