1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.DirectByteBuffer;
13 
14 import hunt.io.ByteBuffer;
15 import hunt.collection.MappedByteBuffer;
16 
17 /+
18 class DirectByteBuffer  : MappedByteBuffer,     DirectBuffer
19 {
20 
21     // Cached unsafe-access object
22     protected static final Unsafe unsafe = Bits.unsafe();
23 
24     // Cached array base offset
25     private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset(byte[].class);
26 
27     // Cached unaligned-access capability
28     protected static final bool unaligned = Bits.unaligned();
29 
30     // Base address, used in all indexing calculations
31     // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
32     //    protected long address;
33 
34     // An object attached to this buffer. If this buffer is a view of another
35     // buffer then we use this field to keep a reference to that buffer to
36     // ensure that its memory isn't freed before we are done with it.
37     private final Object att;
38 
39     public Object attachment() {
40         return att;
41     }
42 
43 
44 
45     private static class Deallocator
46         implements Runnable
47     {
48 
49         private static Unsafe unsafe = Unsafe.getUnsafe();
50 
51         private long address;
52         private long size;
53         private int capacity;
54 
55         private Deallocator(long address, long size, int capacity) {
56             assert (address != 0);
57             this.address = address;
58             this.size = size;
59             this.capacity = capacity;
60         }
61 
62         public void run() {
63             if (address == 0) {
64                 // Paranoia
65                 return;
66             }
67             unsafe.freeMemory(address);
68             address = 0;
69             Bits.unreserveMemory(size, capacity);
70         }
71 
72     }
73 
74     private final Cleaner cleaner;
75 
76     public Cleaner cleaner() { return cleaner; }
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88     // Primary constructor
89     //
90     DirectByteBuffer(int cap) {                   // package-private
91 
92         super(-1, 0, cap, cap);
93         bool pa = VM.isDirectMemoryPageAligned();
94         int ps = Bits.pageSize();
95         long size = Math.max(1L, (long)cap + (pa ? ps : 0));
96         Bits.reserveMemory(size, cap);
97 
98         long base = 0;
99         try {
100             base = unsafe.allocateMemory(size);
101         } catch (OutOfMemoryError x) {
102             Bits.unreserveMemory(size, cap);
103             throw x;
104         }
105         unsafe.setMemory(base, size, (byte) 0);
106         if (pa && (base % ps != 0)) {
107             // Round up to page boundary
108             address = base + ps - (base & (ps - 1));
109         } else {
110             address = base;
111         }
112         cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
113         att = null;
114 
115 
116 
117     }
118 
119 
120 
121     // Invoked to construct a direct ByteBuffer referring to the block of
122     // memory. A given arbitrary object may also be attached to the buffer.
123     //
124     DirectByteBuffer(long addr, int cap, Object ob) {
125         super(-1, 0, cap, cap);
126         address = addr;
127         cleaner = null;
128         att = ob;
129     }
130 
131 
132     // Invoked only by JNI: NewDirectByteBuffer(void*, long)
133     //
134     private DirectByteBuffer(long addr, int cap) {
135         super(-1, 0, cap, cap);
136         address = addr;
137         cleaner = null;
138         att = null;
139     }
140 
141 
142 
143     // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
144     //
145     protected DirectByteBuffer(int cap, long addr,
146                                      FileDescriptor fd,
147                                      Runnable unmapper)
148     {
149 
150         super(-1, 0, cap, cap, fd);
151         address = addr;
152         cleaner = Cleaner.create(this, unmapper);
153         att = null;
154 
155 
156 
157     }
158 
159 
160 
161     // For duplicates and slices
162     //
163     DirectByteBuffer(DirectBuffer db,         // package-private
164                                int mark, int pos, int lim, int cap,
165                                int off)
166     {
167 
168         super(mark, pos, lim, cap);
169         address = db.address() + off;
170 
171         cleaner = null;
172 
173         att = db;
174 
175 
176 
177     }
178 
179     public ByteBuffer slice() {
180         int pos = this.position();
181         int lim = this.limit();
182         assert (pos <= lim);
183         int rem = (pos <= lim ? lim - pos : 0);
184         int off = (pos << 0);
185         assert (off >= 0);
186         return new DirectByteBuffer(this, -1, 0, rem, rem, off);
187     }
188 
189     public ByteBuffer duplicate() {
190         return new DirectByteBuffer(this,
191                                               this.markValue(),
192                                               this.position(),
193                                               this.limit(),
194                                               this.capacity(),
195                                               0);
196     }
197 
198     public ByteBuffer asReadOnlyBuffer() {
199 
200         return new DirectByteBufferR(this,
201                                            this.markValue(),
202                                            this.position(),
203                                            this.limit(),
204                                            this.capacity(),
205                                            0);
206 
207 
208 
209     }
210 
211 
212 
213     public long address() {
214         return address;
215     }
216 
217     private long ix(int i) {
218         return address + ((long)i << 0);
219     }
220 
221     public byte get() {
222         return ((unsafe.getByte(ix(nextGetIndex()))));
223     }
224 
225     public byte get(int i) {
226         return ((unsafe.getByte(ix(checkIndex(i)))));
227     }
228 
229 
230 
231 
232 
233 
234 
235     public ByteBuffer get(byte[] dst, int offset, int length) {
236 
237         if (((long)length << 0) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
238             checkBounds(offset, length, dst.length);
239             int pos = position();
240             int lim = limit();
241             assert (pos <= lim);
242             int rem = (pos <= lim ? lim - pos : 0);
243             if (length > rem)
244                 throw new BufferUnderflowException();
245 
246 
247 
248 
249 
250 
251 
252 
253                 Bits.copyToArray(ix(pos), dst, arrayBaseOffset,
254                                  (long)offset << 0,
255                                  (long)length << 0);
256             position(pos + length);
257         } else {
258             super.get(dst, offset, length);
259         }
260         return this;
261 
262 
263 
264     }
265 
266 
267 
268     public ByteBuffer put(byte x) {
269 
270         unsafe.putByte(ix(nextPutIndex()), ((x)));
271         return this;
272 
273 
274 
275     }
276 
277     public ByteBuffer put(int i, byte x) {
278 
279         unsafe.putByte(ix(checkIndex(i)), ((x)));
280         return this;
281 
282 
283 
284     }
285 
286     public ByteBuffer put(ByteBuffer src) {
287 
288         if (src instanceof DirectByteBuffer) {
289             if (src == this)
290                 throw new IllegalArgumentException();
291             DirectByteBuffer sb = (DirectByteBuffer)src;
292 
293             int spos = sb.position();
294             int slim = sb.limit();
295             assert (spos <= slim);
296             int srem = (spos <= slim ? slim - spos : 0);
297 
298             int pos = position();
299             int lim = limit();
300             assert (pos <= lim);
301             int rem = (pos <= lim ? lim - pos : 0);
302 
303             if (srem > rem)
304                 throw new BufferOverflowException();
305             unsafe.copyMemory(sb.ix(spos), ix(pos), (long)srem << 0);
306             sb.position(spos + srem);
307             position(pos + srem);
308         } else if (src.hb !is null) {
309 
310             int spos = src.position();
311             int slim = src.limit();
312             assert (spos <= slim);
313             int srem = (spos <= slim ? slim - spos : 0);
314 
315             put(src.hb, src.offset + spos, srem);
316             src.position(spos + srem);
317 
318         } else {
319             super.put(src);
320         }
321         return this;
322 
323 
324 
325     }
326 
327     public ByteBuffer put(byte[] src, int offset, int length) {
328 
329         if (((long)length << 0) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
330             checkBounds(offset, length, src.length);
331             int pos = position();
332             int lim = limit();
333             assert (pos <= lim);
334             int rem = (pos <= lim ? lim - pos : 0);
335             if (length > rem)
336                 throw new BufferOverflowException();
337 
338 
339 
340 
341 
342 
343 
344 
345 
346                 Bits.copyFromArray(src, arrayBaseOffset,
347                                    (long)offset << 0,
348                                    ix(pos),
349                                    (long)length << 0);
350             position(pos + length);
351         } else {
352             super.put(src, offset, length);
353         }
354         return this;
355 
356 
357 
358     }
359 
360     public ByteBuffer compact() {
361 
362         int pos = position();
363         int lim = limit();
364         assert (pos <= lim);
365         int rem = (pos <= lim ? lim - pos : 0);
366 
367         unsafe.copyMemory(ix(pos), ix(0), (long)rem << 0);
368         position(rem);
369         limit(capacity());
370         discardMark();
371         return this;
372 
373 
374 
375     }
376 
377     public bool isDirect() {
378         return true;
379     }
380 
381     public bool isReadOnly() {
382         return false;
383     }
384 
385 
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 
397 
398 
399 
400 
401 
402 
403 
404 
405 
406 
407 
408 
409 
410 
411 
412 
413 
414 
415 
416 
417 
418 
419 
420 
421 
422 
423 
424 
425 
426 
427 
428 
429 
430 
431 
432 
433 
434 
435 
436 
437 
438 
439 
440 
441 
442 
443 
444 
445 
446 
447 
448     byte _get(int i) {                          // package-private
449         return unsafe.getByte(address + i);
450     }
451 
452     void _put(int i, byte b) {                  // package-private
453 
454         unsafe.putByte(address + i, b);
455 
456 
457 
458     }
459 
460 
461 
462 
463     private char getChar(long a) {
464         if (unaligned) {
465             char x = unsafe.getChar(a);
466             return (nativeByteOrder ? x : Bits.swap(x));
467         }
468         return Bits.getChar(a, bigEndian);
469     }
470 
471     public char getChar() {
472         return getChar(ix(nextGetIndex((1 << 1))));
473     }
474 
475     public char getChar(int i) {
476         return getChar(ix(checkIndex(i, (1 << 1))));
477     }
478 
479 
480 
481     private ByteBuffer putChar(long a, char x) {
482 
483         if (unaligned) {
484             char y = (x);
485             unsafe.putChar(a, (nativeByteOrder ? y : Bits.swap(y)));
486         } else {
487             Bits.putChar(a, x, bigEndian);
488         }
489         return this;
490 
491 
492 
493     }
494 
495     public ByteBuffer putChar(char x) {
496 
497         putChar(ix(nextPutIndex((1 << 1))), x);
498         return this;
499 
500 
501 
502     }
503 
504     public ByteBuffer putChar(int i, char x) {
505 
506         putChar(ix(checkIndex(i, (1 << 1))), x);
507         return this;
508 
509 
510 
511     }
512 
513     public CharBuffer asCharBuffer() {
514         int off = this.position();
515         int lim = this.limit();
516         assert (off <= lim);
517         int rem = (off <= lim ? lim - off : 0);
518 
519         int size = rem >> 1;
520         if (!unaligned && ((address + off) % (1 << 1) != 0)) {
521             return (bigEndian
522                     ? (CharBuffer)(new ByteBufferAsCharBufferB(this,
523                                                                        -1,
524                                                                        0,
525                                                                        size,
526                                                                        size,
527                                                                        off))
528                     : (CharBuffer)(new ByteBufferAsCharBufferL(this,
529                                                                        -1,
530                                                                        0,
531                                                                        size,
532                                                                        size,
533                                                                        off)));
534         } else {
535             return (nativeByteOrder
536                     ? (CharBuffer)(new DirectCharBufferU(this,
537                                                                  -1,
538                                                                  0,
539                                                                  size,
540                                                                  size,
541                                                                  off))
542                     : (CharBuffer)(new DirectCharBufferS(this,
543                                                                  -1,
544                                                                  0,
545                                                                  size,
546                                                                  size,
547                                                                  off)));
548         }
549     }
550 
551 
552 
553 
554     private short getShort(long a) {
555         if (unaligned) {
556             short x = unsafe.getShort(a);
557             return (nativeByteOrder ? x : Bits.swap(x));
558         }
559         return Bits.getShort(a, bigEndian);
560     }
561 
562     public short getShort() {
563         return getShort(ix(nextGetIndex((1 << 1))));
564     }
565 
566     public short getShort(int i) {
567         return getShort(ix(checkIndex(i, (1 << 1))));
568     }
569 
570 
571 
572     private ByteBuffer putShort(long a, short x) {
573 
574         if (unaligned) {
575             short y = (x);
576             unsafe.putShort(a, (nativeByteOrder ? y : Bits.swap(y)));
577         } else {
578             Bits.putShort(a, x, bigEndian);
579         }
580         return this;
581 
582 
583 
584     }
585 
586     public ByteBuffer putShort(short x) {
587 
588         putShort(ix(nextPutIndex((1 << 1))), x);
589         return this;
590 
591 
592 
593     }
594 
595     public ByteBuffer putShort(int i, short x) {
596 
597         putShort(ix(checkIndex(i, (1 << 1))), x);
598         return this;
599 
600 
601 
602     }
603 
604     public ShortBuffer asShortBuffer() {
605         int off = this.position();
606         int lim = this.limit();
607         assert (off <= lim);
608         int rem = (off <= lim ? lim - off : 0);
609 
610         int size = rem >> 1;
611         if (!unaligned && ((address + off) % (1 << 1) != 0)) {
612             return (bigEndian
613                     ? (ShortBuffer)(new ByteBufferAsShortBufferB(this,
614                                                                        -1,
615                                                                        0,
616                                                                        size,
617                                                                        size,
618                                                                        off))
619                     : (ShortBuffer)(new ByteBufferAsShortBufferL(this,
620                                                                        -1,
621                                                                        0,
622                                                                        size,
623                                                                        size,
624                                                                        off)));
625         } else {
626             return (nativeByteOrder
627                     ? (ShortBuffer)(new DirectShortBufferU(this,
628                                                                  -1,
629                                                                  0,
630                                                                  size,
631                                                                  size,
632                                                                  off))
633                     : (ShortBuffer)(new DirectShortBufferS(this,
634                                                                  -1,
635                                                                  0,
636                                                                  size,
637                                                                  size,
638                                                                  off)));
639         }
640     }
641 
642 
643 
644 
645     private int getInt(long a) {
646         if (unaligned) {
647             int x = unsafe.getInt(a);
648             return (nativeByteOrder ? x : Bits.swap(x));
649         }
650         return Bits.getInt(a, bigEndian);
651     }
652 
653     public int getInt() {
654         return getInt(ix(nextGetIndex((1 << 2))));
655     }
656 
657     public int getInt(int i) {
658         return getInt(ix(checkIndex(i, (1 << 2))));
659     }
660 
661 
662 
663     private ByteBuffer putInt(long a, int x) {
664 
665         if (unaligned) {
666             int y = (x);
667             unsafe.putInt(a, (nativeByteOrder ? y : Bits.swap(y)));
668         } else {
669             Bits.putInt(a, x, bigEndian);
670         }
671         return this;
672 
673 
674 
675     }
676 
677     public ByteBuffer putInt(int x) {
678 
679         putInt(ix(nextPutIndex((1 << 2))), x);
680         return this;
681 
682 
683 
684     }
685 
686     public ByteBuffer putInt(int i, int x) {
687 
688         putInt(ix(checkIndex(i, (1 << 2))), x);
689         return this;
690 
691 
692 
693     }
694 
695     public IntBuffer asIntBuffer() {
696         int off = this.position();
697         int lim = this.limit();
698         assert (off <= lim);
699         int rem = (off <= lim ? lim - off : 0);
700 
701         int size = rem >> 2;
702         if (!unaligned && ((address + off) % (1 << 2) != 0)) {
703             return (bigEndian
704                     ? (IntBuffer)(new ByteBufferAsIntBufferB(this,
705                                                                        -1,
706                                                                        0,
707                                                                        size,
708                                                                        size,
709                                                                        off))
710                     : (IntBuffer)(new ByteBufferAsIntBufferL(this,
711                                                                        -1,
712                                                                        0,
713                                                                        size,
714                                                                        size,
715                                                                        off)));
716         } else {
717             return (nativeByteOrder
718                     ? (IntBuffer)(new DirectIntBufferU(this,
719                                                                  -1,
720                                                                  0,
721                                                                  size,
722                                                                  size,
723                                                                  off))
724                     : (IntBuffer)(new DirectIntBufferS(this,
725                                                                  -1,
726                                                                  0,
727                                                                  size,
728                                                                  size,
729                                                                  off)));
730         }
731     }
732 
733 
734 
735 
736     private long getLong(long a) {
737         if (unaligned) {
738             long x = unsafe.getLong(a);
739             return (nativeByteOrder ? x : Bits.swap(x));
740         }
741         return Bits.getLong(a, bigEndian);
742     }
743 
744     public long getLong() {
745         return getLong(ix(nextGetIndex((1 << 3))));
746     }
747 
748     public long getLong(int i) {
749         return getLong(ix(checkIndex(i, (1 << 3))));
750     }
751 
752 
753 
754     private ByteBuffer putLong(long a, long x) {
755 
756         if (unaligned) {
757             long y = (x);
758             unsafe.putLong(a, (nativeByteOrder ? y : Bits.swap(y)));
759         } else {
760             Bits.putLong(a, x, bigEndian);
761         }
762         return this;
763 
764 
765 
766     }
767 
768     public ByteBuffer putLong(long x) {
769 
770         putLong(ix(nextPutIndex((1 << 3))), x);
771         return this;
772 
773 
774 
775     }
776 
777     public ByteBuffer putLong(int i, long x) {
778 
779         putLong(ix(checkIndex(i, (1 << 3))), x);
780         return this;
781 
782 
783 
784     }
785 
786     public LongBuffer asLongBuffer() {
787         int off = this.position();
788         int lim = this.limit();
789         assert (off <= lim);
790         int rem = (off <= lim ? lim - off : 0);
791 
792         int size = rem >> 3;
793         if (!unaligned && ((address + off) % (1 << 3) != 0)) {
794             return (bigEndian
795                     ? (LongBuffer)(new ByteBufferAsLongBufferB(this,
796                                                                        -1,
797                                                                        0,
798                                                                        size,
799                                                                        size,
800                                                                        off))
801                     : (LongBuffer)(new ByteBufferAsLongBufferL(this,
802                                                                        -1,
803                                                                        0,
804                                                                        size,
805                                                                        size,
806                                                                        off)));
807         } else {
808             return (nativeByteOrder
809                     ? (LongBuffer)(new DirectLongBufferU(this,
810                                                                  -1,
811                                                                  0,
812                                                                  size,
813                                                                  size,
814                                                                  off))
815                     : (LongBuffer)(new DirectLongBufferS(this,
816                                                                  -1,
817                                                                  0,
818                                                                  size,
819                                                                  size,
820                                                                  off)));
821         }
822     }
823 
824 
825 
826 
827     private float getFloat(long a) {
828         if (unaligned) {
829             int x = unsafe.getInt(a);
830             return Float.intBitsToFloat(nativeByteOrder ? x : Bits.swap(x));
831         }
832         return Bits.getFloat(a, bigEndian);
833     }
834 
835     public float getFloat() {
836         return getFloat(ix(nextGetIndex((1 << 2))));
837     }
838 
839     public float getFloat(int i) {
840         return getFloat(ix(checkIndex(i, (1 << 2))));
841     }
842 
843 
844 
845     private ByteBuffer putFloat(long a, float x) {
846 
847         if (unaligned) {
848             int y = Float.floatToRawIntBits(x);
849             unsafe.putInt(a, (nativeByteOrder ? y : Bits.swap(y)));
850         } else {
851             Bits.putFloat(a, x, bigEndian);
852         }
853         return this;
854 
855 
856 
857     }
858 
859     public ByteBuffer putFloat(float x) {
860 
861         putFloat(ix(nextPutIndex((1 << 2))), x);
862         return this;
863 
864 
865 
866     }
867 
868     public ByteBuffer putFloat(int i, float x) {
869 
870         putFloat(ix(checkIndex(i, (1 << 2))), x);
871         return this;
872 
873 
874 
875     }
876 
877     public FloatBuffer asFloatBuffer() {
878         int off = this.position();
879         int lim = this.limit();
880         assert (off <= lim);
881         int rem = (off <= lim ? lim - off : 0);
882 
883         int size = rem >> 2;
884         if (!unaligned && ((address + off) % (1 << 2) != 0)) {
885             return (bigEndian
886                     ? (FloatBuffer)(new ByteBufferAsFloatBufferB(this,
887                                                                        -1,
888                                                                        0,
889                                                                        size,
890                                                                        size,
891                                                                        off))
892                     : (FloatBuffer)(new ByteBufferAsFloatBufferL(this,
893                                                                        -1,
894                                                                        0,
895                                                                        size,
896                                                                        size,
897                                                                        off)));
898         } else {
899             return (nativeByteOrder
900                     ? (FloatBuffer)(new DirectFloatBufferU(this,
901                                                                  -1,
902                                                                  0,
903                                                                  size,
904                                                                  size,
905                                                                  off))
906                     : (FloatBuffer)(new DirectFloatBufferS(this,
907                                                                  -1,
908                                                                  0,
909                                                                  size,
910                                                                  size,
911                                                                  off)));
912         }
913     }
914 
915 
916 
917 
918     private double getDouble(long a) {
919         if (unaligned) {
920             long x = unsafe.getLong(a);
921             return Double.longBitsToDouble(nativeByteOrder ? x : Bits.swap(x));
922         }
923         return Bits.getDouble(a, bigEndian);
924     }
925 
926     public double getDouble() {
927         return getDouble(ix(nextGetIndex((1 << 3))));
928     }
929 
930     public double getDouble(int i) {
931         return getDouble(ix(checkIndex(i, (1 << 3))));
932     }
933 
934 
935 
936     private ByteBuffer putDouble(long a, double x) {
937 
938         if (unaligned) {
939             long y = Double.doubleToRawLongBits(x);
940             unsafe.putLong(a, (nativeByteOrder ? y : Bits.swap(y)));
941         } else {
942             Bits.putDouble(a, x, bigEndian);
943         }
944         return this;
945 
946 
947 
948     }
949 
950     public ByteBuffer putDouble(double x) {
951 
952         putDouble(ix(nextPutIndex((1 << 3))), x);
953         return this;
954 
955 
956 
957     }
958 
959     public ByteBuffer putDouble(int i, double x) {
960 
961         putDouble(ix(checkIndex(i, (1 << 3))), x);
962         return this;
963 
964 
965 
966     }
967 
968     public DoubleBuffer asDoubleBuffer() {
969         int off = this.position();
970         int lim = this.limit();
971         assert (off <= lim);
972         int rem = (off <= lim ? lim - off : 0);
973 
974         int size = rem >> 3;
975         if (!unaligned && ((address + off) % (1 << 3) != 0)) {
976             return (bigEndian
977                     ? (DoubleBuffer)(new ByteBufferAsDoubleBufferB(this,
978                                                                        -1,
979                                                                        0,
980                                                                        size,
981                                                                        size,
982                                                                        off))
983                     : (DoubleBuffer)(new ByteBufferAsDoubleBufferL(this,
984                                                                        -1,
985                                                                        0,
986                                                                        size,
987                                                                        size,
988                                                                        off)));
989         } else {
990             return (nativeByteOrder
991                     ? (DoubleBuffer)(new DirectDoubleBufferU(this,
992                                                                  -1,
993                                                                  0,
994                                                                  size,
995                                                                  size,
996                                                                  off))
997                     : (DoubleBuffer)(new DirectDoubleBufferS(this,
998                                                                  -1,
999                                                                  0,
1000                                                                  size,
1001                                                                  size,
1002                                                                  off)));
1003         }
1004     }
1005 
1006 }
1007 
1008 +/