View Javadoc
1   /*
2    * Copyright 2021 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.buffer.api.unsafe;
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  import io.netty5.util.internal.PlatformDependent;
38  import io.netty5.util.internal.UnsafeAccess;
39  import sun.misc.Unsafe;
40  
41  import java.io.IOException;
42  import java.lang.ref.Reference;
43  import java.nio.ByteBuffer;
44  import java.nio.ByteOrder;
45  import java.nio.ReadOnlyBufferException;
46  import java.nio.channels.FileChannel;
47  import java.nio.channels.ReadableByteChannel;
48  import java.nio.channels.WritableByteChannel;
49  
50  import static io.netty5.buffer.api.internal.Statics.MAX_BUFFER_SIZE;
51  import static io.netty5.buffer.api.internal.Statics.bbslice;
52  import static io.netty5.buffer.api.internal.Statics.bufferIsReadOnly;
53  import static io.netty5.buffer.api.internal.Statics.checkImplicitCapacity;
54  import static io.netty5.buffer.api.internal.Statics.checkLength;
55  import static io.netty5.buffer.api.internal.Statics.nativeAddressWithOffset;
56  import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
57  import static io.netty5.util.internal.PlatformDependent.roundToPowerOfTwo;
58  
59  @UnsafeAccess
60  final class UnsafeBuffer extends AdaptableBuffer<UnsafeBuffer>
61          implements ReadableComponent, WritableComponent, NotReadOnlyReadableComponent, ComponentIterator.Next {
62      private static final int CLOSED_SIZE = -1;
63      private static final boolean ACCESS_UNALIGNED = PlatformDependent.isUnaligned();
64      private static final boolean FLIP_BYTES = ByteOrder.BIG_ENDIAN != ByteOrder.nativeOrder();
65      private static final Unsafe UNSAFE = (Unsafe) PlatformDependent.unwrapUnsafeOrNull();
66      private UnsafeMemory memory; // The memory liveness; monitored by Cleaner.
67      private Object base; // On-heap address reference object, or null for off-heap.
68      private long baseOffset; // Offset of this buffer into the memory.
69      private long address; // Resolved address (baseOffset + memory.address).
70      private int rsize;
71      private int wsize;
72      private boolean readOnly;
73      private int roff;
74      private int woff;
75      private int implicitCapacityLimit;
76  
77      UnsafeBuffer(UnsafeMemory memory, long offset, int size, AllocatorControl control,
78                          Drop<UnsafeBuffer> drop) {
79          super(drop, control);
80          this.memory = memory;
81          base = memory.base;
82          baseOffset = offset;
83          address = memory.address + offset;
84          rsize = size;
85          wsize = size;
86          implicitCapacityLimit = MAX_BUFFER_SIZE;
87      }
88  
89      /**
90       * Constructor for {@linkplain BufferAllocator#constBufferSupplier(byte[]) const buffers}.
91       */
92      private UnsafeBuffer(UnsafeBuffer parent, Drop<UnsafeBuffer> drop) {
93          super(drop, parent.control);
94          implicitCapacityLimit = parent.implicitCapacityLimit;
95          memory = parent.memory;
96          base = parent.base;
97          baseOffset = parent.baseOffset;
98          address = parent.address;
99          rsize = parent.rsize;
100         wsize = parent.wsize;
101         readOnly = parent.readOnly;
102         roff = parent.roff;
103         woff = parent.woff;
104     }
105 
106     @Override
107     public String toString() {
108         return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rsize + ']';
109     }
110 
111     @Override
112     protected RuntimeException createResourceClosedException() {
113         return Statics.bufferIsClosed(this);
114     }
115 
116     @Override
117     public int capacity() {
118         return Math.max(0, rsize); // Use Math.max to make capacity of closed buffer equal to zero.
119     }
120 
121     @Override
122     public int readerOffset() {
123         return roff;
124     }
125 
126     @Override
127     public Buffer readerOffset(int offset) {
128         checkRead(offset, 0);
129         roff = offset;
130         return this;
131     }
132 
133     @Override
134     public int writerOffset() {
135         return woff;
136     }
137 
138     @Override
139     public Buffer writerOffset(int offset) {
140         checkWrite(offset, 0, false);
141         woff = offset;
142         return this;
143     }
144 
145     @Override
146     public int readableBytes() {
147         return super.readableBytes();
148     }
149 
150     @Override
151     public int writableBytes() {
152         return super.writableBytes();
153     }
154 
155     @Override
156     public UnsafeBuffer skipReadableBytes(int delta) {
157         return (UnsafeBuffer) super.skipReadableBytes(delta);
158     }
159 
160     @Override
161     public UnsafeBuffer skipWritableBytes(int delta) {
162         return (UnsafeBuffer) super.skipWritableBytes(delta);
163     }
164 
165     @Override
166     public Buffer fill(byte value) {
167         checkSet(0, capacity());
168         if (rsize == CLOSED_SIZE) {
169             throw bufferIsClosed();
170         }
171         try {
172             PlatformDependent.setMemory(base, address, rsize, value);
173         } finally {
174             Reference.reachabilityFence(memory);
175         }
176         return this;
177     }
178 
179     private long nativeAddress() {
180         return base == null? address : 0;
181     }
182 
183     @Override
184     public Buffer makeReadOnly() {
185         readOnly = true;
186         wsize = CLOSED_SIZE;
187         return this;
188     }
189 
190     @Override
191     public boolean readOnly() {
192         return readOnly;
193     }
194 
195     @Override
196     public boolean isDirect() {
197         return base == null;
198     }
199 
200     @Override
201     public Buffer implicitCapacityLimit(int limit) {
202         checkImplicitCapacity(limit,  capacity());
203         implicitCapacityLimit = limit;
204         return this;
205     }
206 
207     @Override
208     public int implicitCapacityLimit() {
209         return implicitCapacityLimit;
210     }
211 
212     @Override
213     public Buffer copy(int offset, int length, boolean readOnly) {
214         checkLength(length);
215         checkGet(offset, length);
216         if (readOnly && readOnly()) {
217             // If both this buffer and the copy are read-only, they can safely share the memory.
218             UnsafeBuffer copy = newConstChild();
219             copy.baseOffset += offset;
220             copy.address += offset;
221             copy.rsize = length;
222             copy.roff = 0;
223             copy.woff = length;
224             return copy;
225         }
226         Buffer copy = control.getAllocator().allocate(length);
227         try {
228             copyInto(offset, copy, 0, length);
229             copy.writerOffset(length);
230             if (readOnly) {
231                 copy.makeReadOnly();
232             }
233             return copy;
234         } catch (Throwable e) {
235             copy.close();
236             throw e;
237         }
238     }
239 
240     @Override
241     public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
242         checkCopyIntoArgs(srcPos, length, destPos, dest.length);
243         copyIntoArray(srcPos, dest, destPos, length);
244     }
245 
246     private void copyIntoArray(int srcPos, byte[] dest, int destPos, int length) {
247         long destOffset = PlatformDependent.byteArrayBaseOffset();
248         try {
249             PlatformDependent.copyMemory(base, address + srcPos, dest, destOffset + destPos, length);
250         } finally {
251             Reference.reachabilityFence(memory);
252             Reference.reachabilityFence(dest);
253         }
254     }
255 
256     @Override
257     public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
258         checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
259         if (dest.isReadOnly()) {
260             throw new ReadOnlyBufferException();
261         }
262         if (dest.hasArray()) {
263             copyIntoArray(srcPos, dest.array(), dest.arrayOffset() + destPos, length);
264         } else {
265             assert dest.isDirect();
266             long destAddr = PlatformDependent.directBufferAddress(dest);
267             try {
268                 PlatformDependent.copyMemory(base, address + srcPos, null, destAddr + destPos, length);
269             } finally {
270                 Reference.reachabilityFence(memory);
271                 Reference.reachabilityFence(dest);
272             }
273         }
274     }
275 
276     private void checkCopyIntoArgs(int srcPos, int length, int destPos, int destLength) {
277         if (rsize == CLOSED_SIZE) {
278             throw bufferIsClosed();
279         }
280         if (srcPos < 0) {
281             throw new IndexOutOfBoundsException("The srcPos cannot be negative: " + srcPos + '.');
282         }
283         checkLength(length);
284         if (rsize < srcPos + length) {
285             throw new IndexOutOfBoundsException("The srcPos + length is beyond the end of the buffer: " +
286                     "srcPos = " + srcPos + ", length = " + length + '.');
287         }
288         if (destPos < 0) {
289             throw new IndexOutOfBoundsException("The destPos cannot be negative: " + destPos + '.');
290         }
291         if (destLength < destPos + length) {
292             throw new IndexOutOfBoundsException("The destPos + length is beyond the end of the destination: " +
293                     "destPos = " + destPos + ", length = " + length + '.');
294         }
295     }
296 
297     @Override
298     public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
299         if (!dest.isAccessible()) {
300             throw Statics.bufferIsClosed(dest);
301         }
302         checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
303         if (dest.readOnly()) {
304             throw bufferIsReadOnly(this);
305         }
306         try {
307             if (dest instanceof UnsafeBuffer) {
308                 UnsafeBuffer destUnsafe = (UnsafeBuffer) dest;
309                 long nativeAddress = destUnsafe.nativeAddress();
310                 if (nativeAddress != 0) {
311                     PlatformDependent.copyMemory(base, address + srcPos, null, nativeAddress + destPos, length);
312                 } else {
313                     PlatformDependent.copyMemory(
314                             base, address + srcPos, destUnsafe.base, destUnsafe.address + destPos, length);
315                 }
316             } else {
317                 Statics.copyToViaReverseLoop(this, srcPos, dest, destPos, length);
318             }
319         } finally {
320             Reference.reachabilityFence(memory);
321             Reference.reachabilityFence(dest);
322         }
323     }
324 
325     @Override
326     public int transferTo(WritableByteChannel channel, int length) throws IOException {
327         if (!isAccessible()) {
328             throw bufferIsClosed();
329         }
330         length = Math.min(readableBytes(), length);
331         if (length == 0) {
332             return 0;
333         }
334         checkGet(readerOffset(), length);
335         int bytesWritten = channel.write(readableBuffer().limit(length));
336         skipReadableBytes(bytesWritten);
337         return bytesWritten;
338     }
339 
340     @Override
341     public int transferFrom(FileChannel channel, long position, int length) throws IOException {
342         checkPositiveOrZero(position, "position");
343         checkPositiveOrZero(length, "length");
344         if (!isAccessible()) {
345             throw bufferIsClosed();
346         }
347         if (readOnly()) {
348             throw bufferIsReadOnly(this);
349         }
350         length = Math.min(writableBytes(), length);
351         if (length == 0) {
352             return 0;
353         }
354         checkSet(writerOffset(), length);
355         int bytesRead = channel.read(writableBuffer().limit(length), position);
356         if (bytesRead > 0) { // Don't skipWritable if bytesRead is 0 or -1
357             skipWritableBytes(bytesRead);
358         }
359         return bytesRead;
360     }
361 
362     @Override
363     public int transferFrom(ReadableByteChannel channel, int length) throws IOException {
364         if (!isAccessible()) {
365             throw bufferIsClosed();
366         }
367         if (readOnly()) {
368             throw bufferIsReadOnly(this);
369         }
370         length = Math.min(writableBytes(), length);
371         if (length == 0) {
372             return 0;
373         }
374         checkSet(writerOffset(), length);
375         int bytesRead = channel.read(writableBuffer().limit(length));
376         if (bytesRead != -1) {
377             skipWritableBytes(bytesRead);
378         }
379         return bytesRead;
380     }
381 
382     /**
383      * Most deployment platforms support unaligned access, and are little-endian.
384      * This allows us to micro-optimise for this common case.
385      */
386     private static final boolean BYTES_BEFORE_USE_LITTLE_ENDIAN =
387             PlatformDependent.isUnaligned() && ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN;
388 
389     @Override
390     public int bytesBefore(byte needle) {
391         // For the details of this algorithm, see Hacker's Delight, Chapter 6, Searching Words.
392         // Richard Startin also describes this on his blog: https://richardstartin.github.io/posts/finding-bytes
393         if (!isAccessible()) {
394             throw bufferIsClosed();
395         }
396         try {
397             int offset = roff;
398             final int length = woff - roff;
399             final int end = woff;
400             final long addr = address;
401 
402             if (length > 7) {
403                 final long pattern = (needle & 0xFFL) * 0x101010101010101L;
404                 for (final int longEnd = offset + (length >>> 3) * Long.BYTES;
405                      offset < longEnd;
406                      offset += Long.BYTES) {
407                     final long word = BYTES_BEFORE_USE_LITTLE_ENDIAN?
408                             PlatformDependent.getLong(base, addr + offset) :
409                             loadLong(addr + offset);
410 
411                     final long input = word ^ pattern;
412                     final long tmp =
413                             ~((input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL | input | 0x7F7F7F7F7F7F7F7FL);
414                     final int binaryPosition = BYTES_BEFORE_USE_LITTLE_ENDIAN?
415                             Long.numberOfTrailingZeros(tmp) :
416                             Long.numberOfLeadingZeros(tmp);
417 
418                     if (binaryPosition < Long.SIZE) {
419                         return offset + (binaryPosition >>> 3) - roff;
420                     }
421                 }
422             }
423             for (; offset < end; offset++) {
424                 if (loadByte(addr + offset) == needle) {
425                     return offset - roff;
426                 }
427             }
428 
429             return -1;
430         } finally {
431             Reference.reachabilityFence(memory);
432         }
433     }
434 
435     @Override
436     public int bytesBefore(Buffer needle) {
437         try {
438             UncheckedLoadByte uncheckedLoadByte = UnsafeBuffer::uncheckedLoadByte;
439             return Statics.bytesBefore(this, uncheckedLoadByte,
440                                        needle, needle instanceof UnsafeBuffer ? uncheckedLoadByte : null);
441         } finally {
442             Reference.reachabilityFence(memory);
443         }
444     }
445 
446     /**
447      * Used by {@link #bytesBefore(Buffer)}.
448      */
449     private static byte uncheckedLoadByte(Buffer buffer, int offset) {
450         UnsafeBuffer unsafeBuffer = (UnsafeBuffer) buffer;
451         return UNSAFE.getByte(unsafeBuffer.base, unsafeBuffer.address + offset);
452     }
453 
454     @Override
455     public ByteCursor openCursor() {
456         return openCursor(readerOffset(), readableBytes());
457     }
458 
459     @Override
460     public ByteCursor openCursor(int fromOffset, int length) {
461         if (rsize == CLOSED_SIZE) {
462             throw bufferIsClosed();
463         }
464         if (fromOffset < 0) {
465             throw new IndexOutOfBoundsException("The fromOffset cannot be negative: " + fromOffset + '.');
466         }
467         checkLength(length);
468         if (capacity() < fromOffset + length) {
469             throw new IndexOutOfBoundsException("The fromOffset + length is beyond the end of the buffer: " +
470                     "fromOffset = " + fromOffset + ", length = " + length + '.');
471         }
472         return new ForwardUnsafeByteCursor(memory, base, address, fromOffset, length);
473     }
474 
475     @Override
476     public ByteCursor openReverseCursor(int fromOffset, int length) {
477         if (rsize == CLOSED_SIZE) {
478             throw bufferIsClosed();
479         }
480         if (fromOffset < 0) {
481             throw new IndexOutOfBoundsException("The fromOffset cannot be negative: " + fromOffset + '.');
482         }
483         checkLength(length);
484         if (capacity() <= fromOffset) {
485             throw new IndexOutOfBoundsException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
486         }
487         if (fromOffset - length < -1) {
488             throw new IndexOutOfBoundsException("The fromOffset - length would underflow the buffer: " +
489                     "fromOffset = " + fromOffset + ", length = " + length + '.');
490         }
491         return new ReverseUnsafeByteCursor(memory, base, address, fromOffset, length);
492     }
493 
494     @Override
495     public Buffer ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
496         if (!isAccessible()) {
497             throw bufferIsClosed();
498         }
499         if (!isOwned()) {
500             throw attachTrace(new IllegalStateException(
501                     "Buffer is not owned. Only owned buffers can call ensureWritable."));
502         }
503         if (size < 0) {
504             throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
505         }
506         if (minimumGrowth < 0) {
507             throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
508         }
509         if (rsize != wsize) {
510             throw bufferIsReadOnly(this);
511         }
512         if (writableBytes() >= size) {
513             // We already have enough space.
514             return this;
515         }
516 
517         if (allowCompaction && writableBytes() + readerOffset() >= size) {
518             // We can solve this with compaction.
519             return compact();
520         }
521 
522         // Allocate a bigger buffer.
523         long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
524         Statics.assertValidBufferSize(newSize);
525         UnsafeBuffer buffer = (UnsafeBuffer) control.getAllocator().allocate((int) newSize);
526 
527         // Copy contents.
528         try {
529             copyInto(0, buffer, 0, capacity());
530         } finally {
531             Reference.reachabilityFence(memory);
532             Reference.reachabilityFence(buffer.memory);
533         }
534 
535         // Release the old memory, and install the new memory:
536         Drop<UnsafeBuffer> drop = buffer.unsafeGetDrop();
537         disconnectDrop(drop);
538         attachNewMemory(buffer.memory, drop);
539         return this;
540     }
541 
542     private Drop<UnsafeBuffer> disconnectDrop(Drop<UnsafeBuffer> newDrop) {
543         var drop = (Drop<UnsafeBuffer>) unsafeGetDrop();
544         int roff = this.roff;
545         int woff = this.woff;
546         drop.drop(this);
547         unsafeSetDrop(newDrop);
548         this.roff = roff;
549         this.woff = woff;
550         return drop;
551     }
552 
553     private void attachNewMemory(UnsafeMemory memory, Drop<UnsafeBuffer> drop) {
554         this.memory = memory;
555         base = memory.base;
556         baseOffset = 0;
557         address = memory.address;
558         rsize = memory.size;
559         wsize = memory.size;
560         drop.attach(this);
561     }
562 
563     @Override
564     public Buffer split(int splitOffset) {
565         if (splitOffset < 0) {
566             throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
567         }
568         if (capacity() < splitOffset) {
569             throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
570                     "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
571         }
572         if (!isAccessible()) {
573             throw bufferIsClosed();
574         }
575         if (!isOwned()) {
576             throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned."));
577         }
578         var drop = unsafeGetDrop().fork();
579         var splitBuffer = new UnsafeBuffer(memory, baseOffset, splitOffset, control, drop);
580         drop.attach(splitBuffer);
581         splitBuffer.woff = Math.min(woff, splitOffset);
582         splitBuffer.roff = Math.min(roff, splitOffset);
583         boolean readOnly = readOnly();
584         if (readOnly) {
585             splitBuffer.makeReadOnly();
586         }
587         // Split preserves const-state.
588         rsize -= splitOffset;
589         baseOffset += splitOffset;
590         address += splitOffset;
591         if (!readOnly) {
592             wsize = rsize;
593         }
594         woff = Math.max(woff, splitOffset) - splitOffset;
595         roff = Math.max(roff, splitOffset) - splitOffset;
596         return splitBuffer;
597     }
598 
599     @Override
600     public Buffer compact() {
601         if (!isAccessible()) {
602             throw bufferIsClosed();
603         }
604         if (!isOwned()) {
605             throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact."));
606         }
607         if (readOnly()) {
608             throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only.");
609         }
610         if (roff == 0) {
611             return this;
612         }
613         try {
614             PlatformDependent.copyMemory(base, address + roff, base, address, woff - roff);
615         } finally {
616             Reference.reachabilityFence(memory);
617         }
618         woff -= roff;
619         roff = 0;
620         return this;
621     }
622 
623     @Override
624     public int countComponents() {
625         return 1;
626     }
627 
628     @Override
629     public int countReadableComponents() {
630         return readableBytes() > 0? 1 : 0;
631     }
632 
633     @Override
634     public int countWritableComponents() {
635         return writableBytes() > 0? 1 : 0;
636     }
637 
638     // <editor-fold defaultstate="collapsed" desc="Readable/WritableComponent implementation.">
639     @Override
640     public boolean hasReadableArray() {
641         return base instanceof byte[];
642     }
643 
644     @Override
645     public byte[] readableArray() {
646         checkHasReadableArray();
647         return (byte[]) base;
648     }
649 
650     @Override
651     public int readableArrayOffset() {
652         checkHasReadableArray();
653         return Math.toIntExact(address + roff - PlatformDependent.byteArrayBaseOffset());
654     }
655 
656     private void checkHasReadableArray() {
657         if (!hasReadableArray()) {
658             throw new UnsupportedOperationException("No readable array available.");
659         }
660     }
661 
662     @Override
663     public int readableArrayLength() {
664         return woff - roff;
665     }
666 
667     @Override
668     public long readableNativeAddress() {
669         return nativeAddressWithOffset(nativeAddress(), roff);
670     }
671 
672     @Override
673     public ByteBuffer readableBuffer() {
674         return mutableReadableBuffer().asReadOnlyBuffer();
675     }
676 
677     @Override
678     public ByteBuffer mutableReadableBuffer() {
679         final ByteBuffer buf;
680         if (hasReadableArray()) {
681             buf = bbslice(ByteBuffer.wrap(readableArray()), readableArrayOffset(), readableArrayLength());
682         } else {
683             buf = PlatformDependent.directBuffer(address + roff, readableBytes(), memory);
684         }
685         return buf;
686     }
687 
688     @Override
689     public boolean hasWritableArray() {
690         return hasReadableArray();
691     }
692 
693     @Override
694     public byte[] writableArray() {
695         checkHasWritableArray();
696         return (byte[]) base;
697     }
698 
699     @Override
700     public int writableArrayOffset() {
701         checkHasWritableArray();
702         return Math.toIntExact(address + woff - PlatformDependent.byteArrayBaseOffset());
703     }
704 
705     private void checkHasWritableArray() {
706         if (!hasReadableArray()) {
707             throw new UnsupportedOperationException("No writable array available.");
708         }
709     }
710 
711     @Override
712     public int writableArrayLength() {
713         return capacity() - woff;
714     }
715 
716     @Override
717     public long writableNativeAddress() {
718         return nativeAddressWithOffset(nativeAddress(), woff);
719     }
720 
721     @Override
722     public ByteBuffer writableBuffer() {
723         final ByteBuffer buf;
724         if (hasWritableArray()) {
725             buf = bbslice(ByteBuffer.wrap(writableArray()), writableArrayOffset(), writableArrayLength());
726         } else {
727             buf = PlatformDependent.directBuffer(address + woff, writableBytes(), memory);
728         }
729         return buf;
730     }
731 
732     @Override
733     public <N extends Next> N next() {
734         return null; // There is no "next" component in our external-iteration of components.
735     }
736     // </editor-fold>
737 
738     @Override
739     public <E extends Exception> int forEachReadable(int initialIndex, ReadableComponentProcessor<E> processor)
740             throws E {
741         if (!isAccessible()) {
742             throw bufferIsClosed();
743         }
744         int readableBytes = readableBytes();
745         if (readableBytes == 0) {
746             return 0;
747         }
748         checkRead(readerOffset(), readableBytes);
749         try {
750             return processor.process(initialIndex, this)? 1 : -1;
751         } finally {
752             Reference.reachabilityFence(this);
753         }
754     }
755 
756     @Override
757     public <T extends ReadableComponent & Next> ComponentIterator<T> forEachReadable() {
758         return new SingleComponentIterator<>(acquire(), readableBytes() > 0 ? this : null);
759     }
760 
761     @Override
762     public <E extends Exception> int forEachWritable(int initialIndex, WritableComponentProcessor<E> processor)
763             throws E {
764         if (!isAccessible()) {
765             throw bufferIsClosed();
766         }
767         int writableBytes = writableBytes();
768         if (writableBytes == 0) {
769             return 0;
770         }
771         checkWrite(writerOffset(), writableBytes, false);
772         try {
773             return processor.process(initialIndex, this)? 1 : -1;
774         } finally {
775             Reference.reachabilityFence(this);
776         }
777     }
778 
779     @Override
780     public <T extends WritableComponent & Next> ComponentIterator<T> forEachWritable() {
781         checkWrite(writerOffset(), writableBytes(), false);
782         return new SingleComponentIterator<>(acquire(), writableBytes() > 0 ? this : null);
783     }
784 
785     // <editor-fold defaultstate="collapsed" desc="Primitive accessors implementation.">
786     @Override
787     public byte readByte() {
788         checkRead(roff, Byte.BYTES);
789         try {
790             var value = loadByte(address + roff);
791             roff += Byte.BYTES;
792             return value;
793         } finally {
794             Reference.reachabilityFence(memory);
795         }
796     }
797 
798     @Override
799     public byte getByte(int roff) {
800         checkGet(roff, Byte.BYTES);
801         try {
802             return loadByte(address + roff);
803         } finally {
804             Reference.reachabilityFence(memory);
805         }
806     }
807 
808     @Override
809     public int readUnsignedByte() {
810         return readByte() & 0xFF;
811     }
812 
813     @Override
814     public int getUnsignedByte(int roff) {
815         return getByte(roff) & 0xFF;
816     }
817 
818     @Override
819     public Buffer writeByte(byte value) {
820         checkWrite(woff, Byte.BYTES, true);
821         long offset = address + woff;
822         woff += Byte.BYTES;
823         try {
824             storeByte(offset, value);
825         } finally {
826             Reference.reachabilityFence(memory);
827         }
828         return this;
829     }
830 
831     @Override
832     public Buffer setByte(int woff, byte value) {
833         checkSet(woff, Byte.BYTES);
834         long offset = address + woff;
835         try {
836             storeByte(offset, value);
837         } finally {
838             Reference.reachabilityFence(memory);
839         }
840         return this;
841     }
842 
843     @Override
844     public Buffer writeUnsignedByte(int value) {
845         checkWrite(woff, Byte.BYTES, true);
846         long offset = address + woff;
847         woff += Byte.BYTES;
848         try {
849             storeByte(offset, (byte) (value & 0xFF));
850         } finally {
851             Reference.reachabilityFence(memory);
852         }
853         return this;
854     }
855 
856     @Override
857     public Buffer setUnsignedByte(int woff, int value) {
858         checkSet(woff, Byte.BYTES);
859         long offset = address + woff;
860         try {
861             storeByte(offset, (byte) (value & 0xFF));
862         } finally {
863             Reference.reachabilityFence(memory);
864         }
865         return this;
866     }
867 
868     @Override
869     public char readChar() {
870         checkRead(roff, Character.BYTES);
871         try {
872             long offset = address + roff;
873             roff += Character.BYTES;
874             return loadChar(offset);
875         } finally {
876             Reference.reachabilityFence(memory);
877         }
878     }
879 
880     @Override
881     public char getChar(int roff) {
882         checkGet(roff, Character.BYTES);
883         try {
884             long offset = address + roff;
885             return loadChar(offset);
886         } finally {
887             Reference.reachabilityFence(memory);
888         }
889     }
890 
891     @Override
892     public Buffer writeChar(char value) {
893         checkWrite(woff, Character.BYTES, true);
894         long offset = address + woff;
895         woff += Character.BYTES;
896         try {
897             storeChar(offset, value);
898         } finally {
899             Reference.reachabilityFence(memory);
900         }
901         return this;
902     }
903 
904     @Override
905     public Buffer setChar(int woff, char value) {
906         checkSet(woff, Character.BYTES);
907         long offset = address + woff;
908         try {
909             storeChar(offset, value);
910         } finally {
911             Reference.reachabilityFence(memory);
912         }
913         return this;
914     }
915 
916     @Override
917     public short readShort() {
918         checkRead(roff, Short.BYTES);
919         try {
920             long offset = address + roff;
921             roff += Short.BYTES;
922             return loadShort(offset);
923         } finally {
924             Reference.reachabilityFence(memory);
925         }
926     }
927 
928     @Override
929     public short getShort(int roff) {
930         checkGet(roff, Short.BYTES);
931         try {
932             long offset = address + roff;
933             return loadShort(offset);
934         } finally {
935             Reference.reachabilityFence(memory);
936         }
937     }
938 
939     @Override
940     public int readUnsignedShort() {
941         return readShort() & 0xFFFF;
942     }
943 
944     @Override
945     public int getUnsignedShort(int roff) {
946         return getShort(roff) & 0xFFFF;
947     }
948 
949     @Override
950     public Buffer writeShort(short value) {
951         checkWrite(woff, Short.BYTES, true);
952         long offset = address + woff;
953         woff += Short.BYTES;
954         try {
955             storeShort(offset, value);
956         } finally {
957             Reference.reachabilityFence(memory);
958         }
959         return this;
960     }
961 
962     @Override
963     public Buffer setShort(int woff, short value) {
964         checkSet(woff, Short.BYTES);
965         long offset = address + woff;
966         try {
967             storeShort(offset, value);
968         } finally {
969             Reference.reachabilityFence(memory);
970         }
971         return this;
972     }
973 
974     @Override
975     public Buffer writeUnsignedShort(int value) {
976         checkWrite(woff, Short.BYTES, true);
977         long offset = address + woff;
978         woff += Short.BYTES;
979         try {
980             storeShort(offset, (short) (value & 0xFFFF));
981         } finally {
982             Reference.reachabilityFence(memory);
983         }
984         return this;
985     }
986 
987     @Override
988     public Buffer setUnsignedShort(int woff, int value) {
989         checkSet(woff, Short.BYTES);
990         long offset = address + woff;
991         try {
992             storeShort(offset, (short) (value & 0xFFFF));
993         } finally {
994             Reference.reachabilityFence(memory);
995         }
996         return this;
997     }
998 
999     @Override
1000     public int readMedium() {
1001         checkRead(roff, 3);
1002         long offset = address + roff;
1003         int value = loadByte(offset) << 16 | (loadByte(offset + 1) & 0xFF) << 8 | loadByte(offset + 2) & 0xFF;
1004         roff += 3;
1005         return value;
1006     }
1007 
1008     @Override
1009     public int getMedium(int roff) {
1010         checkGet(roff, 3);
1011         long offset = address + roff;
1012         return loadByte(offset) << 16 | (loadByte(offset + 1) & 0xFF) << 8 | loadByte(offset + 2) & 0xFF;
1013     }
1014 
1015     @Override
1016     public int readUnsignedMedium() {
1017         checkRead(roff, 3);
1018         long offset = address + roff;
1019         int value =
1020                 (loadByte(offset) << 16 | (loadByte(offset + 1) & 0xFF) << 8 | loadByte(offset + 2) & 0xFF) & 0xFFFFFF;
1021         roff += 3;
1022         return value;
1023     }
1024 
1025     @Override
1026     public int getUnsignedMedium(int roff) {
1027         checkGet(roff, 3);
1028         long offset = address + roff;
1029         return (loadByte(offset) << 16 | (loadByte(offset + 1) & 0xFF) << 8 | loadByte(offset + 2) & 0xFF) & 0xFFFFFF;
1030     }
1031 
1032     @Override
1033     public Buffer writeMedium(int value) {
1034         checkWrite(woff, 3, true);
1035         long offset = address + woff;
1036         storeByte(offset, (byte) (value >> 16));
1037         storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
1038         storeByte(offset + 2, (byte) (value & 0xFF));
1039         woff += 3;
1040         return this;
1041     }
1042 
1043     @Override
1044     public Buffer setMedium(int woff, int value) {
1045         checkSet(woff, 3);
1046         long offset = address + woff;
1047         storeByte(offset, (byte) (value >> 16));
1048         storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
1049         storeByte(offset + 2, (byte) (value & 0xFF));
1050         return this;
1051     }
1052 
1053     @Override
1054     public Buffer writeUnsignedMedium(int value) {
1055         checkWrite(woff, 3, true);
1056         long offset = address + woff;
1057         storeByte(offset, (byte) (value >> 16));
1058         storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
1059         storeByte(offset + 2, (byte) (value & 0xFF));
1060         woff += 3;
1061         return this;
1062     }
1063 
1064     @Override
1065     public Buffer setUnsignedMedium(int woff, int value) {
1066         checkSet(woff, 3);
1067         long offset = address + woff;
1068         storeByte(offset, (byte) (value >> 16));
1069         storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
1070         storeByte(offset + 2, (byte) (value & 0xFF));
1071         return this;
1072     }
1073 
1074     @Override
1075     public int readInt() {
1076         checkRead(roff, Integer.BYTES);
1077         try {
1078             long offset = address + roff;
1079             roff += Integer.BYTES;
1080             return loadInt(offset);
1081         } finally {
1082             Reference.reachabilityFence(memory);
1083         }
1084     }
1085 
1086     @Override
1087     public int getInt(int roff) {
1088         checkGet(roff, Integer.BYTES);
1089         try {
1090             long offset = address + roff;
1091             return loadInt(offset);
1092         } finally {
1093             Reference.reachabilityFence(memory);
1094         }
1095     }
1096 
1097     @Override
1098     public long readUnsignedInt() {
1099         return readInt() & 0x0000_0000_FFFF_FFFFL;
1100     }
1101 
1102     @Override
1103     public long getUnsignedInt(int roff) {
1104         return getInt(roff) & 0x0000_0000_FFFF_FFFFL;
1105     }
1106 
1107     @Override
1108     public Buffer writeInt(int value) {
1109         checkWrite(woff, Integer.BYTES, true);
1110         long offset = address + woff;
1111         woff += Integer.BYTES;
1112         try {
1113             storeInt(offset, value);
1114         } finally {
1115             Reference.reachabilityFence(memory);
1116         }
1117         return this;
1118     }
1119 
1120     @Override
1121     public Buffer setInt(int woff, int value) {
1122         checkSet(woff, Integer.BYTES);
1123         long offset = address + woff;
1124         try {
1125             storeInt(offset, value);
1126         } finally {
1127             Reference.reachabilityFence(memory);
1128         }
1129         return this;
1130     }
1131 
1132     @Override
1133     public Buffer writeUnsignedInt(long value) {
1134         checkWrite(woff, Integer.BYTES, true);
1135         long offset = address + woff;
1136         woff += Integer.BYTES;
1137         try {
1138             storeInt(offset, (int) (value & 0xFFFF_FFFFL));
1139         } finally {
1140             Reference.reachabilityFence(memory);
1141         }
1142         return this;
1143     }
1144 
1145     @Override
1146     public Buffer setUnsignedInt(int woff, long value) {
1147         checkSet(woff, Integer.BYTES);
1148         long offset = address + woff;
1149         try {
1150             storeInt(offset, (int) (value & 0xFFFF_FFFFL));
1151         } finally {
1152             Reference.reachabilityFence(memory);
1153         }
1154         return this;
1155     }
1156 
1157     @Override
1158     public float readFloat() {
1159         checkRead(roff, Float.BYTES);
1160         try {
1161             long offset = address + roff;
1162             roff += Float.BYTES;
1163             return loadFloat(offset);
1164         } finally {
1165             Reference.reachabilityFence(memory);
1166         }
1167     }
1168 
1169     @Override
1170     public float getFloat(int roff) {
1171         checkGet(roff, Float.BYTES);
1172         try {
1173             long offset = address + roff;
1174             return loadFloat(offset);
1175         } finally {
1176             Reference.reachabilityFence(memory);
1177         }
1178     }
1179 
1180     @Override
1181     public Buffer writeFloat(float value) {
1182         checkWrite(woff, Float.BYTES, true);
1183         long offset = address + woff;
1184         woff += Float.BYTES;
1185         try {
1186             storeFloat(offset, value);
1187         } finally {
1188             Reference.reachabilityFence(memory);
1189         }
1190         return this;
1191     }
1192 
1193     @Override
1194     public Buffer setFloat(int woff, float value) {
1195         checkSet(woff, Float.BYTES);
1196         long offset = address + woff;
1197         try {
1198             storeFloat(offset, value);
1199         } finally {
1200             Reference.reachabilityFence(memory);
1201         }
1202         return this;
1203     }
1204 
1205     @Override
1206     public long readLong() {
1207         checkRead(roff, Long.BYTES);
1208         try {
1209             long offset = address + roff;
1210             roff += Long.BYTES;
1211             return loadLong(offset);
1212         } finally {
1213             Reference.reachabilityFence(memory);
1214         }
1215     }
1216 
1217     @Override
1218     public long getLong(int roff) {
1219         checkGet(roff, Long.BYTES);
1220         try {
1221             long offset = address + roff;
1222             return loadLong(offset);
1223         } finally {
1224             Reference.reachabilityFence(memory);
1225         }
1226     }
1227 
1228     @Override
1229     public Buffer writeLong(long value) {
1230         checkWrite(woff, Long.BYTES, true);
1231         long offset = address + woff;
1232         woff += Long.BYTES;
1233         try {
1234             storeLong(offset, value);
1235         } finally {
1236             Reference.reachabilityFence(memory);
1237         }
1238         return this;
1239     }
1240 
1241     @Override
1242     public Buffer setLong(int woff, long value) {
1243         checkSet(woff, Long.BYTES);
1244         long offset = address + woff;
1245         try {
1246             storeLong(offset, value);
1247         } finally {
1248             Reference.reachabilityFence(memory);
1249         }
1250         return this;
1251     }
1252 
1253     @Override
1254     public double readDouble() {
1255         checkRead(roff, Double.BYTES);
1256         try {
1257             long offset = address + roff;
1258             roff += Double.BYTES;
1259             return loadDouble(offset);
1260         } finally {
1261             Reference.reachabilityFence(memory);
1262         }
1263     }
1264 
1265     @Override
1266     public double getDouble(int roff) {
1267         checkGet(roff, Double.BYTES);
1268         try {
1269             long offset = address + roff;
1270             return loadDouble(offset);
1271         } finally {
1272             Reference.reachabilityFence(memory);
1273         }
1274     }
1275 
1276     @Override
1277     public Buffer writeDouble(double value) {
1278         checkWrite(woff, Double.BYTES, true);
1279         long offset = address + woff;
1280         woff += Double.BYTES;
1281         try {
1282             storeDouble(offset, value);
1283         } finally {
1284             Reference.reachabilityFence(memory);
1285         }
1286         return this;
1287     }
1288 
1289     @Override
1290     public Buffer setDouble(int woff, double value) {
1291         checkSet(woff, Double.BYTES);
1292         long offset = address + woff;
1293         try {
1294             storeDouble(offset, value);
1295         } finally {
1296             Reference.reachabilityFence(memory);
1297         }
1298         return this;
1299     }
1300     // </editor-fold>
1301 
1302     @Override
1303     protected Owned<UnsafeBuffer> prepareSend() {
1304         int roff = this.roff;
1305         int woff = this.woff;
1306         boolean readOnly = readOnly();
1307         int implicitCapacityLimit = this.implicitCapacityLimit;
1308         UnsafeMemory memory = this.memory;
1309         AllocatorControl control = this.control;
1310         long baseOffset = this.baseOffset;
1311         int rsize = this.rsize;
1312         return drop -> {
1313             UnsafeBuffer copy = new UnsafeBuffer(memory, baseOffset, rsize, control, drop);
1314             copy.roff = roff;
1315             copy.woff = woff;
1316             copy.implicitCapacityLimit = implicitCapacityLimit;
1317             if (readOnly) {
1318                 copy.makeReadOnly();
1319             }
1320             return copy;
1321         };
1322     }
1323 
1324     @Override
1325     protected void makeInaccessible() {
1326         roff = 0;
1327         woff = 0;
1328         rsize = CLOSED_SIZE;
1329         wsize = CLOSED_SIZE;
1330         readOnly = false;
1331     }
1332 
1333     private void checkRead(int index, int size) {
1334         if (index < 0 | woff < index + size) {
1335             throw readAccessCheckException(index, size);
1336         }
1337     }
1338 
1339     private void checkGet(int index, int size) {
1340         if (index < 0 | rsize < index + size) {
1341             throw readAccessCheckException(index, size);
1342         }
1343     }
1344 
1345     private void checkWrite(int index, int size, boolean mayExpand) {
1346         if (index < roff | wsize < index + size) {
1347             handleWriteAccessBoundsFailure(index, size, mayExpand);
1348         }
1349     }
1350 
1351     private void checkSet(int index, int size) {
1352         if (index < 0 | wsize < index + size) {
1353             handleWriteAccessBoundsFailure(index, size, false);
1354         }
1355     }
1356 
1357     private RuntimeException readAccessCheckException(int index, int size) {
1358         if (rsize == CLOSED_SIZE) {
1359             throw bufferIsClosed();
1360         }
1361         return outOfBounds(index, size);
1362     }
1363 
1364     private void handleWriteAccessBoundsFailure(int index, int size, boolean mayExpand) {
1365         if (rsize == CLOSED_SIZE) {
1366             throw bufferIsClosed();
1367         }
1368         if (wsize != rsize) {
1369             throw bufferIsReadOnly(this);
1370         }
1371         int capacity = capacity();
1372         if (mayExpand && index >= 0 && index <= capacity && woff + size <= implicitCapacityLimit && isOwned()) {
1373             // Grow into next power-of-two, but not beyond the implicit limit.
1374             int minimumGrowth = Math.min(
1375                     Math.max(roundToPowerOfTwo(capacity * 2), size),
1376                     implicitCapacityLimit) - capacity;
1377             ensureWritable(size, minimumGrowth, false);
1378             checkSet(index, size); // Verify writing is now possible, without recursing.
1379             return;
1380         }
1381         throw outOfBounds(index, size);
1382     }
1383 
1384     private BufferClosedException bufferIsClosed() {
1385         return attachTrace(Statics.bufferIsClosed(this));
1386     }
1387 
1388     private IndexOutOfBoundsException outOfBounds(int index, int size) {
1389         return new IndexOutOfBoundsException(
1390                 "Access at index " + index + " of size " + size + " is out of bounds: " +
1391                 "[read 0 to " + woff + ", write 0 to " + rsize + "].");
1392     }
1393 
1394     private byte loadByte(long off) {
1395         return PlatformDependent.getByte(base, off);
1396     }
1397 
1398     private char loadChar(long offset) {
1399         if (ACCESS_UNALIGNED) {
1400             var value = PlatformDependent.getChar(base, offset);
1401             return FLIP_BYTES? Character.reverseBytes(value) : value;
1402         }
1403         return loadCharUnaligned(offset);
1404     }
1405 
1406     private char loadCharUnaligned(long offset) {
1407         final char value;
1408         Object b = base;
1409         if ((offset & 1) == 0) {
1410             value = PlatformDependent.getChar(b, offset);
1411         } else {
1412             value = (char) (PlatformDependent.getByte(b, offset) << 8 |
1413                     PlatformDependent.getByte(b, offset + 1));
1414         }
1415         return FLIP_BYTES? Character.reverseBytes(value) : value;
1416     }
1417 
1418     private short loadShort(long offset) {
1419         if (ACCESS_UNALIGNED) {
1420             var value = PlatformDependent.getShort(base, offset);
1421             return FLIP_BYTES? Short.reverseBytes(value) : value;
1422         }
1423         return loadShortUnaligned(offset);
1424     }
1425 
1426     private short loadShortUnaligned(long offset) {
1427         final short value;
1428         Object b = base;
1429         if ((offset & 1) == 0) {
1430             value = PlatformDependent.getShort(b, offset);
1431         } else {
1432             value = (short) (PlatformDependent.getByte(b, offset) << 8 |
1433                     PlatformDependent.getByte(b, offset + 1));
1434         }
1435         return FLIP_BYTES? Short.reverseBytes(value) : value;
1436     }
1437 
1438     private int loadInt(long offset) {
1439         if (ACCESS_UNALIGNED) {
1440             var value = PlatformDependent.getInt(base, offset);
1441             return FLIP_BYTES? Integer.reverseBytes(value) : value;
1442         }
1443         return loadIntUnaligned(offset);
1444     }
1445 
1446     private int loadIntUnaligned(long offset) {
1447         final int value;
1448         Object b = base;
1449         if ((offset & 3) == 0) {
1450             value = PlatformDependent.getInt(b, offset);
1451         } else if ((offset & 1) == 0) {
1452             value = PlatformDependent.getShort(b, offset) << 16 |
1453                     PlatformDependent.getShort(b, offset + 2);
1454         } else {
1455             value = PlatformDependent.getByte(b, offset) << 24 |
1456                     PlatformDependent.getByte(b, offset + 1) << 16 |
1457                     PlatformDependent.getByte(b, offset + 2) << 8 |
1458                     PlatformDependent.getByte(b, offset + 3);
1459         }
1460         return FLIP_BYTES? Integer.reverseBytes(value) : value;
1461     }
1462 
1463     private float loadFloat(long offset) {
1464         if (ACCESS_UNALIGNED) {
1465             if (FLIP_BYTES) {
1466                 var value = PlatformDependent.getInt(base, offset);
1467                 return Float.intBitsToFloat(Integer.reverseBytes(value));
1468             }
1469             return PlatformDependent.getFloat(base, offset);
1470         }
1471         return loadFloatUnaligned(offset);
1472     }
1473 
1474     private float loadFloatUnaligned(long offset) {
1475         return Float.intBitsToFloat(loadIntUnaligned(offset));
1476     }
1477 
1478     private long loadLong(long offset) {
1479         if (ACCESS_UNALIGNED) {
1480             var value = PlatformDependent.getLong(base, offset);
1481             return FLIP_BYTES? Long.reverseBytes(value) : value;
1482         }
1483         return loadLongUnaligned(offset);
1484     }
1485 
1486     private long loadLongUnaligned(long offset) {
1487         final long value;
1488         Object b = base;
1489         if ((offset & 7) == 0) {
1490             value = PlatformDependent.getLong(b, offset);
1491         } else if ((offset & 3) == 0) {
1492             value = (long) PlatformDependent.getInt(b, offset) << 32 |
1493                     PlatformDependent.getInt(b, offset + 4);
1494         } else if ((offset & 1) == 0) {
1495             value = (long) PlatformDependent.getShort(b, offset) << 48 |
1496                     (long) PlatformDependent.getShort(b, offset + 2) << 32 |
1497                     (long) PlatformDependent.getShort(b, offset + 4) << 16 |
1498                     PlatformDependent.getShort(b, offset + 6);
1499         } else {
1500             value = (long) PlatformDependent.getByte(b, offset) << 54 |
1501                     (long) PlatformDependent.getByte(b, offset + 1) << 48 |
1502                     (long) PlatformDependent.getByte(b, offset + 2) << 40 |
1503                     (long) PlatformDependent.getByte(b, offset + 3) << 32 |
1504                     (long) PlatformDependent.getByte(b, offset + 4) << 24 |
1505                     (long) PlatformDependent.getByte(b, offset + 5) << 16 |
1506                     (long) PlatformDependent.getByte(b, offset + 6) << 8 |
1507                     PlatformDependent.getByte(b, offset + 7);
1508         }
1509         return FLIP_BYTES? Long.reverseBytes(value) : value;
1510     }
1511 
1512     private double loadDouble(long offset) {
1513         if (ACCESS_UNALIGNED) {
1514             if (FLIP_BYTES) {
1515                 var value = PlatformDependent.getLong(base, offset);
1516                 return Double.longBitsToDouble(Long.reverseBytes(value));
1517             }
1518             return PlatformDependent.getDouble(base, offset);
1519         }
1520         return loadDoubleUnaligned(offset);
1521     }
1522 
1523     private double loadDoubleUnaligned(long offset) {
1524         return Double.longBitsToDouble(loadLongUnaligned(offset));
1525     }
1526 
1527     private void storeByte(long offset, byte value) {
1528         PlatformDependent.putByte(base, offset, value);
1529     }
1530 
1531     private void storeChar(long offset, char value) {
1532         if (FLIP_BYTES) {
1533             value = Character.reverseBytes(value);
1534         }
1535         if (ACCESS_UNALIGNED) {
1536             PlatformDependent.putChar(base, offset, value);
1537         } else {
1538             storeCharUnaligned(offset, value);
1539         }
1540     }
1541 
1542     private void storeCharUnaligned(long offset, char value) {
1543         Object b = base;
1544         if ((offset & 1) == 0) {
1545             PlatformDependent.putChar(b, offset, value);
1546         } else {
1547             PlatformDependent.putByte(b, offset, (byte) (value >> 8));
1548             PlatformDependent.putByte(b, offset + 1, (byte) value);
1549         }
1550     }
1551 
1552     private void storeShort(long offset, short value) {
1553         if (FLIP_BYTES) {
1554             value = Short.reverseBytes(value);
1555         }
1556         if (ACCESS_UNALIGNED) {
1557             PlatformDependent.putShort(base, offset, value);
1558         } else {
1559             storeShortUnaligned(offset, value);
1560         }
1561     }
1562 
1563     private void storeShortUnaligned(long offset, short value) {
1564         Object b = base;
1565         if ((offset & 1) == 0) {
1566             PlatformDependent.putShort(b, offset, value);
1567         } else {
1568             PlatformDependent.putByte(b, offset, (byte) (value >> 8));
1569             PlatformDependent.putByte(b, offset + 1, (byte) value);
1570         }
1571     }
1572 
1573     private void storeInt(long offset, int value) {
1574         if (FLIP_BYTES) {
1575             value = Integer.reverseBytes(value);
1576         }
1577         if (ACCESS_UNALIGNED) {
1578             PlatformDependent.putInt(base, offset, value);
1579         } else {
1580             storeIntUnaligned(offset, value);
1581         }
1582     }
1583 
1584     private void storeIntUnaligned(long offset, int value) {
1585         Object b = base;
1586         if ((offset & 3) == 0) {
1587             PlatformDependent.putInt(b, offset, value);
1588         } else if ((offset & 1) == 0) {
1589             PlatformDependent.putShort(b, offset, (short) (value >> 16));
1590             PlatformDependent.putShort(b, offset + 2, (short) value);
1591         } else {
1592             PlatformDependent.putByte(b, offset, (byte) (value >> 24));
1593             PlatformDependent.putByte(b, offset + 1, (byte) (value >> 16));
1594             PlatformDependent.putByte(b, offset + 2, (byte) (value >> 8));
1595             PlatformDependent.putByte(b, offset + 3, (byte) value);
1596         }
1597     }
1598 
1599     private void storeFloat(long offset, float value) {
1600         storeInt(offset, Float.floatToRawIntBits(value));
1601     }
1602 
1603     private void storeLong(long offset, long value) {
1604         if (FLIP_BYTES) {
1605             value = Long.reverseBytes(value);
1606         }
1607         if (ACCESS_UNALIGNED) {
1608             PlatformDependent.putLong(base, offset, value);
1609         } else {
1610             storeLongUnaligned(offset, value);
1611         }
1612     }
1613 
1614     private void storeLongUnaligned(long offset, long value) {
1615         Object b = base;
1616         if ((offset & 7) == 0) {
1617             PlatformDependent.putLong(b, offset, value);
1618         } else if ((offset & 3) == 0) {
1619             PlatformDependent.putInt(b, offset, (int) (value >> 32));
1620             PlatformDependent.putInt(b, offset + 4, (int) value);
1621         } else if ((offset & 1) == 0) {
1622             PlatformDependent.putShort(b, offset, (short) (value >> 48));
1623             PlatformDependent.putShort(b, offset + 16, (short) (value >> 32));
1624             PlatformDependent.putShort(b, offset + 32, (short) (value >> 16));
1625             PlatformDependent.putShort(b, offset + 48, (short) value);
1626         } else {
1627             PlatformDependent.putByte(b, offset, (byte) (value >> 56));
1628             PlatformDependent.putByte(b, offset + 1, (byte) (value >> 48));
1629             PlatformDependent.putByte(b, offset + 2, (byte) (value >> 40));
1630             PlatformDependent.putByte(b, offset + 3, (byte) (value >> 32));
1631             PlatformDependent.putByte(b, offset + 4, (byte) (value >> 24));
1632             PlatformDependent.putByte(b, offset + 5, (byte) (value >> 16));
1633             PlatformDependent.putByte(b, offset + 6, (byte) (value >> 8));
1634             PlatformDependent.putByte(b, offset + 7, (byte) value);
1635         }
1636     }
1637 
1638     private void storeDouble(long offset, double value) {
1639         storeLong(offset, Double.doubleToRawLongBits(value));
1640     }
1641 
1642     Object recover() {
1643         return memory;
1644     }
1645 
1646     UnsafeBuffer newConstChild() {
1647         assert readOnly();
1648         Drop<UnsafeBuffer> drop = unsafeGetDrop().fork();
1649         UnsafeBuffer child = new UnsafeBuffer(this, drop);
1650         drop.attach(child);
1651         return child;
1652     }
1653 
1654     private static final class ForwardUnsafeByteCursor implements ByteCursor {
1655         final UnsafeMemory memory; // Keep memory alive.
1656         final Object baseObj;
1657         final long baseAddress;
1658         int index;
1659         final int end;
1660         byte byteValue;
1661 
1662         ForwardUnsafeByteCursor(UnsafeMemory memory, Object base, long address, int fromOffset, int length) {
1663             this.memory = memory;
1664             baseObj = base;
1665             baseAddress = address;
1666             index = fromOffset;
1667             end = index + length;
1668             byteValue = -1;
1669         }
1670 
1671         @Override
1672         public boolean readByte() {
1673             if (index < end) {
1674                 try {
1675                     byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
1676                 } finally {
1677                     Reference.reachabilityFence(memory);
1678                 }
1679                 index++;
1680                 return true;
1681             }
1682             return false;
1683         }
1684 
1685         @Override
1686         public byte getByte() {
1687             return byteValue;
1688         }
1689 
1690         @Override
1691         public int currentOffset() {
1692             return index;
1693         }
1694 
1695         @Override
1696         public int bytesLeft() {
1697             return end - index;
1698         }
1699     }
1700 
1701     private static final class ReverseUnsafeByteCursor implements ByteCursor {
1702         final UnsafeMemory memory; // Keep memory alive.
1703         final Object baseObj;
1704         final long baseAddress;
1705         int index;
1706         final int end;
1707         byte byteValue;
1708 
1709         ReverseUnsafeByteCursor(UnsafeMemory memory, Object base, long address, int fromOffset, int length) {
1710             this.memory = memory;
1711             baseObj = base;
1712             baseAddress = address;
1713             index = fromOffset;
1714             end = index - length;
1715             byteValue = -1;
1716         }
1717 
1718         @Override
1719         public boolean readByte() {
1720             if (index > end) {
1721                 try {
1722                     byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
1723                 } finally {
1724                     Reference.reachabilityFence(memory);
1725                 }
1726                 index--;
1727                 return true;
1728             }
1729             return false;
1730         }
1731 
1732         @Override
1733         public byte getByte() {
1734             return byteValue;
1735         }
1736 
1737         @Override
1738         public int currentOffset() {
1739             return index;
1740         }
1741 
1742         @Override
1743         public int bytesLeft() {
1744             return index - end;
1745         }
1746     }
1747 }