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 +/