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