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.ByteBuffer; 13 14 import hunt.Byte; 15 import hunt.collection.Buffer; 16 import hunt.collection.StringBuffer; 17 import hunt.Exceptions; 18 import hunt.text.StringBuilder; 19 20 import std.bitmanip; 21 22 23 /** 24 * 25 */ 26 abstract class ByteBuffer : Buffer { 27 protected byte[] hb; // Non-null only for heap buffers 28 29 protected int offset; 30 31 protected bool bigEndian = true; // package-private 32 33 // bool nativeByteOrder // package-private 34 // = (Bits.byteOrder() == ByteOrder.BIG_ENDIAN); 35 36 /** 37 * Retrieves this buffer's byte order. 38 * 39 * <p> The byte order is used when reading or writing multibyte values, and 40 * when creating buffers that are views of this byte buffer. The order of 41 * a newly-created byte buffer is always {@link ByteOrder#BIG_ENDIAN 42 * BIG_ENDIAN}. </p> 43 * 44 * @return This buffer's byte order 45 */ 46 final ByteOrder order() { 47 return bigEndian ? ByteOrder.BigEndian : ByteOrder.LittleEndian; 48 } 49 50 /** 51 * Modifies this buffer's byte order. 52 * 53 * @param bo 54 * The new byte order, 55 * either {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN} 56 * or {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN} 57 * 58 * @return This buffer 59 */ 60 final ByteBuffer order(ByteOrder bo) { 61 bigEndian = (bo == ByteOrder.BigEndian); 62 // nativeByteOrder = 63 // (bigEndian == (Bits.byteOrder() == ByteOrder.BigEndian)); 64 return this; 65 } 66 67 // Creates a new buffer with the given mark, position, limit, capacity, 68 // backing array, and array offset 69 this(int mark, int pos, int lim, int cap, // package-private 70 byte[] hb, int offset) { 71 super(mark, pos, lim, cap); 72 this.hb = hb; 73 this.offset = offset; 74 } 75 76 // Creates a new buffer with the given mark, position, limit, and capacity 77 this(int mark, int pos, int lim, int cap) { // package-private 78 this(mark, pos, lim, cap, null, 0); 79 } 80 81 // this(int capacity = 1024) 82 // { 83 // super(capacity); 84 // } 85 86 /** 87 * Allocates a new direct byte buffer. 88 * 89 * <p> The new buffer's position will be zero, its limit will be its 90 * capacity, its mark will be undefined, and each of its elements will be 91 * initialized to zero. Whether or not it has a 92 * {@link #hasArray backing array} is unspecified. 93 * 94 * @param capacity 95 * The new buffer's capacity, in bytes 96 * 97 * @return The new byte buffer 98 * 99 * @throws IllegalArgumentException 100 * If the <tt>capacity</tt> is a negative integer 101 */ 102 deprecated("Using BufferUtils.allocateDirect instead.") 103 static ByteBuffer allocateDirect(int capacity) { 104 throw new NotSupportedException("deprecated"); 105 } 106 107 /** 108 * Allocates a new byte buffer. 109 * 110 * <p> The new buffer's position will be zero, its limit will be its 111 * capacity, its mark will be undefined, and each of its elements will be 112 * initialized to zero. It will have a {@link #array backing array}, 113 * and its {@link #arrayOffset array offset} will be zero. 114 * 115 * @param capacity 116 * The new buffer's capacity, in bytes 117 * 118 * @return The new byte buffer 119 * 120 * @throws IllegalArgumentException 121 * If the <tt>capacity</tt> is a negative integer 122 */ 123 124 deprecated("Using BufferUtils.allocate instead.") 125 static ByteBuffer allocate(size_t capacity) { 126 throw new NotSupportedException("deprecated"); 127 } 128 129 /** 130 * Wraps a byte array into a buffer. 131 * 132 * <p> The new buffer will be backed by the given byte array; 133 * that is, modifications to the buffer will cause the array to be modified 134 * and vice versa. The new buffer's capacity will be 135 * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit 136 * will be <tt>offset + length</tt>, and its mark will be undefined. Its 137 * {@link #array backing array} will be the given array, and 138 * its {@link #arrayOffset array offset} will be zero. </p> 139 * 140 * @param array 141 * The array that will back the new buffer 142 * 143 * @param offset 144 * The offset of the subarray to be used; must be non-negative and 145 * no larger than <tt>array.length</tt>. The new buffer's position 146 * will be set to this value. 147 * 148 * @param length 149 * The length of the subarray to be used; 150 * must be non-negative and no larger than 151 * <tt>array.length - offset</tt>. 152 * The new buffer's limit will be set to <tt>offset + length</tt>. 153 * 154 * @return The new byte buffer 155 * 156 * @throws IndexOutOfBoundsException 157 * If the preconditions on the <tt>offset</tt> and <tt>length</tt> 158 * parameters do not hold 159 */ 160 deprecated("Using BufferUtils.toBuffer instead.") 161 static ByteBuffer wrap(byte[] array, int offset, int length) { 162 throw new NotSupportedException("deprecated"); 163 } 164 165 /** 166 * Wraps a byte array into a buffer. 167 * 168 * <p> The new buffer will be backed by the given byte array; 169 * that is, modifications to the buffer will cause the array to be modified 170 * and vice versa. The new buffer's capacity and limit will be 171 * <tt>array.length</tt>, its position will be zero, and its mark will be 172 * undefined. Its {@link #array backing array} will be the 173 * given array, and its {@link #arrayOffset array offset>} will 174 * be zero. </p> 175 * 176 * @param array 177 * The array that will back this buffer 178 * 179 * @return The new byte buffer 180 */ 181 deprecated("Using BufferUtils.toBuffer instead.") 182 static ByteBuffer wrap(byte[] array) { 183 throw new NotSupportedException("deprecated"); 184 } 185 186 /** 187 * Creates a new byte buffer whose content is a shared subsequence of 188 * this buffer's content. 189 * 190 * <p> The content of the new buffer will start at this buffer's current 191 * position. Changes to this buffer's content will be visible in the new 192 * buffer, and vice versa; the two buffers' position, limit, and mark 193 * values will be independent. 194 * 195 * <p> The new buffer's position will be zero, its capacity and its limit 196 * will be the number of bytes remaining in this buffer, and its mark 197 * will be undefined. The new buffer will be direct if, and only if, this 198 * buffer is direct, and it will be read-only if, and only if, this buffer 199 * is read-only. </p> 200 * 201 * @return The new byte buffer 202 */ 203 abstract ByteBuffer slice(); 204 205 // void clear() 206 // { 207 // hb = null; 208 // position = 0; 209 // limit = 0; 210 // } 211 212 /** 213 * Creates a new byte buffer that shares this buffer's content. 214 * 215 * <p> The content of the new buffer will be that of this buffer. Changes 216 * to this buffer's content will be visible in the new buffer, and vice 217 * versa; the two buffers' position, limit, and mark values will be 218 * independent. 219 * 220 * <p> The new buffer's capacity, limit, position, and mark values will be 221 * identical to those of this buffer. The new buffer will be direct if, 222 * and only if, this buffer is direct, and it will be read-only if, and 223 * only if, this buffer is read-only. </p> 224 * 225 * @return The new byte buffer 226 */ 227 abstract ByteBuffer duplicate(); 228 229 /** 230 * Creates a new, read-only byte buffer that shares this buffer's 231 * content. 232 * 233 * <p> The content of the new buffer will be that of this buffer. Changes 234 * to this buffer's content will be visible in the new buffer; the new 235 * buffer itself, however, will be read-only and will not allow the shared 236 * content to be modified. The two buffers' position, limit, and mark 237 * values will be independent. 238 * 239 * <p> The new buffer's capacity, limit, position, and mark values will be 240 * identical to those of this buffer. 241 * 242 * <p> If this buffer is itself read-only then this method behaves in 243 * exactly the same way as the {@link #duplicate duplicate} method. </p> 244 * 245 * @return The new, read-only byte buffer 246 */ 247 abstract ByteBuffer asReadOnlyBuffer(); 248 249 // -- Singleton get/put methods -- 250 251 /** 252 * Relative <i>get</i> method. Reads the byte at this buffer's 253 * current position, and then increments the position. 254 * 255 * @return The byte at the buffer's current position 256 * 257 * @throws BufferUnderflowException 258 * If the buffer's current position is not smaller than its limit 259 */ 260 abstract byte get(); 261 262 /** 263 * Relative <i>put</i> method <i>(optional operation)</i>. 264 * 265 * <p> Writes the given byte into this buffer at the current 266 * position, and then increments the position. </p> 267 * 268 * @param b 269 * The byte to be written 270 * 271 * @return This buffer 272 * 273 * @throws BufferOverflowException 274 * If this buffer's current position is not smaller than its limit 275 * 276 * @throws ReadOnlyBufferException 277 * If this buffer is read-only 278 */ 279 abstract ByteBuffer put(byte b); 280 281 /** 282 * Absolute <i>get</i> method. Reads the byte at the given 283 * index. 284 * 285 * @param index 286 * The index from which the byte will be read 287 * 288 * @return The byte at the given index 289 * 290 * @throws IndexOutOfBoundsException 291 * If <tt>index</tt> is negative 292 * or not smaller than the buffer's limit 293 */ 294 abstract byte get(int index); 295 296 /** 297 * Absolute <i>put</i> method <i>(optional operation)</i>. 298 * 299 * <p> Writes the given byte into this buffer at the given 300 * index. </p> 301 * 302 * @param index 303 * The index at which the byte will be written 304 * 305 * @param b 306 * The byte value to be written 307 * 308 * @return This buffer 309 * 310 * @throws IndexOutOfBoundsException 311 * If <tt>index</tt> is negative 312 * or not smaller than the buffer's limit 313 * 314 * @throws ReadOnlyBufferException 315 * If this buffer is read-only 316 */ 317 abstract ByteBuffer put(int index, byte b); 318 319 // -- Bulk get operations -- 320 321 /** 322 * Relative bulk <i>get</i> method. 323 * 324 * <p> This method transfers bytes from this buffer into the given 325 * destination array. If there are fewer bytes remaining in the 326 * buffer than are required to satisfy the request, that is, if 327 * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no 328 * bytes are transferred and a {@link BufferUnderflowException} is 329 * thrown. 330 * 331 * <p> Otherwise, this method copies <tt>length</tt> bytes from this 332 * buffer into the given array, starting at the current position of this 333 * buffer and at the given offset in the array. The position of this 334 * buffer is then incremented by <tt>length</tt>. 335 * 336 * <p> In other words, an invocation of this method of the form 337 * <tt>src.get(dst, off, len)</tt> has exactly the same effect as 338 * the loop 339 * 340 * <pre>{@code 341 * for (int i = off; i < off + len; i++) 342 * dst[i] = src.get(): 343 * }</pre> 344 * 345 * except that it first checks that there are sufficient bytes in 346 * this buffer and it is potentially much more efficient. 347 * 348 * @param dst 349 * The array into which bytes are to be written 350 * 351 * @param offset 352 * The offset within the array of the first byte to be 353 * written; must be non-negative and no larger than 354 * <tt>dst.length</tt> 355 * 356 * @param length 357 * The maximum number of bytes to be written to the given 358 * array; must be non-negative and no larger than 359 * <tt>dst.length - offset</tt> 360 * 361 * @return This buffer 362 * 363 * @throws BufferUnderflowException 364 * If there are fewer than <tt>length</tt> bytes 365 * remaining in this buffer 366 * 367 * @throws IndexOutOfBoundsException 368 * If the preconditions on the <tt>offset</tt> and <tt>length</tt> 369 * parameters do not hold 370 */ 371 ByteBuffer get(byte[] dst, int offset, int length) { 372 checkBounds(offset, length, cast(int) dst.length); 373 if (length > remaining()) 374 throw new BufferUnderflowException(""); 375 int end = offset + length; 376 for (int i = offset; i < end; i++) 377 dst[i] = get(); 378 return this; 379 } 380 381 /** 382 * Relative bulk <i>get</i> method. 383 * 384 * <p> This method transfers bytes from this buffer into the given 385 * destination array. An invocation of this method of the form 386 * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation 387 * 388 * <pre> 389 * src.get(a, 0, a.length) </pre> 390 * 391 * @param dst 392 * The destination array 393 * 394 * @return This buffer 395 * 396 * @throws BufferUnderflowException 397 * If there are fewer than <tt>length</tt> bytes 398 * remaining in this buffer 399 */ 400 ByteBuffer get(byte[] dst) { 401 return get(dst, 0, cast(int) dst.length); 402 } 403 404 // -- Bulk put operations -- 405 406 /** 407 * Relative bulk <i>put</i> method <i>(optional operation)</i>. 408 * 409 * <p> This method transfers the bytes remaining in the given source 410 * buffer into this buffer. If there are more bytes remaining in the 411 * source buffer than in this buffer, that is, if 412 * <tt>src.remaining()</tt> <tt>></tt> <tt>remaining()</tt>, 413 * then no bytes are transferred and a {@link 414 * BufferOverflowException} is thrown. 415 * 416 * <p> Otherwise, this method copies 417 * <i>n</i> = <tt>src.remaining()</tt> bytes from the given 418 * buffer into this buffer, starting at each buffer's current position. 419 * The positions of both buffers are then incremented by <i>n</i>. 420 * 421 * <p> In other words, an invocation of this method of the form 422 * <tt>dst.put(src)</tt> has exactly the same effect as the loop 423 * 424 * <pre> 425 * while (src.hasRemaining()) 426 * dst.put(src.get()); </pre> 427 * 428 * except that it first checks that there is sufficient space in this 429 * buffer and it is potentially much more efficient. 430 * 431 * @param src 432 * The source buffer from which bytes are to be read; 433 * must not be this buffer 434 * 435 * @return This buffer 436 * 437 * @throws BufferOverflowException 438 * If there is insufficient space in this buffer 439 * for the remaining bytes in the source buffer 440 * 441 * @throws IllegalArgumentException 442 * If the source buffer is this buffer 443 * 444 * @throws ReadOnlyBufferException 445 * If this buffer is read-only 446 */ 447 ByteBuffer put(ByteBuffer src) { 448 if (src == this) 449 throw new IllegalArgumentException(""); 450 if (isReadOnly()) 451 throw new ReadOnlyBufferException(""); 452 int n = src.remaining(); 453 if (n > remaining()) 454 throw new BufferOverflowException(""); 455 for (int i = 0; i < n; i++) 456 put(src.get()); 457 return this; 458 } 459 460 /** 461 * Relative bulk <i>put</i> method <i>(optional operation)</i>. 462 * 463 * <p> This method transfers bytes into this buffer from the given 464 * source array. If there are more bytes to be copied from the array 465 * than remain in this buffer, that is, if 466 * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no 467 * bytes are transferred and a {@link BufferOverflowException} is 468 * thrown. 469 * 470 * <p> Otherwise, this method copies <tt>length</tt> bytes from the 471 * given array into this buffer, starting at the given offset in the array 472 * and at the current position of this buffer. The position of this buffer 473 * is then incremented by <tt>length</tt>. 474 * 475 * <p> In other words, an invocation of this method of the form 476 * <tt>dst.put(src, off, len)</tt> has exactly the same effect as 477 * the loop 478 * 479 * <pre>{@code 480 * for (int i = off; i < off + len; i++) 481 * dst.put(a[i]); 482 * }</pre> 483 * 484 * except that it first checks that there is sufficient space in this 485 * buffer and it is potentially much more efficient. 486 * 487 * @param src 488 * The array from which bytes are to be read 489 * 490 * @param offset 491 * The offset within the array of the first byte to be read; 492 * must be non-negative and no larger than <tt>array.length</tt> 493 * 494 * @param length 495 * The number of bytes to be read from the given array; 496 * must be non-negative and no larger than 497 * <tt>array.length - offset</tt> 498 * 499 * @return This buffer 500 * 501 * @throws BufferOverflowException 502 * If there is insufficient space in this buffer 503 * 504 * @throws IndexOutOfBoundsException 505 * If the preconditions on the <tt>offset</tt> and <tt>length</tt> 506 * parameters do not hold 507 * 508 * @throws ReadOnlyBufferException 509 * If this buffer is read-only 510 */ 511 ByteBuffer put(byte[] src, int offset, int length) { 512 checkBounds(offset, length, cast(int) src.length); 513 if (length > remaining()) 514 throw new BufferOverflowException(""); 515 int end = offset + length; 516 for (int i = offset; i < end; i++) 517 this.put(src[i]); 518 return this; 519 } 520 521 /** 522 * Relative bulk <i>put</i> method <i>(optional operation)</i>. 523 * 524 * <p> This method transfers the entire content of the given source 525 * byte array into this buffer. An invocation of this method of the 526 * form <tt>dst.put(a)</tt> behaves in exactly the same way as the 527 * invocation 528 * 529 * <pre> 530 * dst.put(a, 0, a.length) </pre> 531 * 532 * @param src 533 * The source array 534 * 535 * @return This buffer 536 * 537 * @throws BufferOverflowException 538 * If there is insufficient space in this buffer 539 * 540 * @throws ReadOnlyBufferException 541 * If this buffer is read-only 542 */ 543 final ByteBuffer put(byte[] src) { 544 return put(src, 0, cast(int) src.length); 545 } 546 547 final ByteBuffer put(string src) { 548 return put(cast(byte[]) src, 0, cast(int) src.length); 549 } 550 551 /** 552 * Relative <i>get</i> method for reading a short value. 553 * 554 * <p> Reads the next two bytes at this buffer's current position, 555 * composing them into a short value according to the current byte order, 556 * and then increments the position by two. </p> 557 * 558 * @return The short value at the buffer's current position 559 * 560 * @throws BufferUnderflowException 561 * If there are fewer than two bytes 562 * remaining in this buffer 563 */ 564 abstract short getShort(); 565 566 /** 567 * Relative <i>put</i> method for writing a short 568 * value <i>(optional operation)</i>. 569 * 570 * <p> Writes two bytes containing the given short value, in the 571 * current byte order, into this buffer at the current position, and then 572 * increments the position by two. </p> 573 * 574 * @param value 575 * The short value to be written 576 * 577 * @return This buffer 578 * 579 * @throws BufferOverflowException 580 * If there are fewer than two bytes 581 * remaining in this buffer 582 * 583 * @throws ReadOnlyBufferException 584 * If this buffer is read-only 585 */ 586 abstract ByteBuffer putShort(short value); 587 588 /** 589 * Absolute <i>get</i> method for reading a short value. 590 * 591 * <p> Reads two bytes at the given index, composing them into a 592 * short value according to the current byte order. </p> 593 * 594 * @param index 595 * The index from which the bytes will be read 596 * 597 * @return The short value at the given index 598 * 599 * @throws IndexOutOfBoundsException 600 * If <tt>index</tt> is negative 601 * or not smaller than the buffer's limit, 602 * minus one 603 */ 604 abstract short getShort(int index); 605 606 /** 607 * Absolute <i>put</i> method for writing a short 608 * value <i>(optional operation)</i>. 609 * 610 * <p> Writes two bytes containing the given short value, in the 611 * current byte order, into this buffer at the given index. </p> 612 * 613 * @param index 614 * The index at which the bytes will be written 615 * 616 * @param value 617 * The short value to be written 618 * 619 * @return This buffer 620 * 621 * @throws IndexOutOfBoundsException 622 * If <tt>index</tt> is negative 623 * or not smaller than the buffer's limit, 624 * minus one 625 * 626 * @throws ReadOnlyBufferException 627 * If this buffer is read-only 628 */ 629 abstract ByteBuffer putShort(int index, short value); 630 631 /** 632 * Relative <i>get</i> method for reading an int value. 633 * 634 * <p> Reads the next four bytes at this buffer's current position, 635 * composing them into an int value according to the current byte order, 636 * and then increments the position by four. </p> 637 * 638 * @return The int value at the buffer's current position 639 * 640 * @throws BufferUnderflowException 641 * If there are fewer than four bytes 642 * remaining in this buffer 643 */ 644 abstract int getInt(); 645 646 /** 647 * Relative <i>put</i> method for writing an int 648 * value <i>(optional operation)</i>. 649 * 650 * <p> Writes four bytes containing the given int value, in the 651 * current byte order, into this buffer at the current position, and then 652 * increments the position by four. </p> 653 * 654 * @param value 655 * The int value to be written 656 * 657 * @return This buffer 658 * 659 * @throws BufferOverflowException 660 * If there are fewer than four bytes 661 * remaining in this buffer 662 * 663 * @throws ReadOnlyBufferException 664 * If this buffer is read-only 665 */ 666 abstract ByteBuffer putInt(int value); 667 668 /** 669 * Absolute <i>get</i> method for reading an int value. 670 * 671 * <p> Reads four bytes at the given index, composing them into a 672 * int value according to the current byte order. </p> 673 * 674 * @param index 675 * The index from which the bytes will be read 676 * 677 * @return The int value at the given index 678 * 679 * @throws IndexOutOfBoundsException 680 * If {@code index} is negative 681 * or not smaller than the buffer's limit, 682 * minus three 683 */ 684 abstract int getInt(int index); 685 686 /** 687 * Absolute <i>put</i> method for writing an int 688 * value <i>(optional operation)</i>. 689 * 690 * <p> Writes four bytes containing the given int value, in the 691 * current byte order, into this buffer at the given index. </p> 692 * 693 * @param index 694 * The index at which the bytes will be written 695 * 696 * @param value 697 * The int value to be written 698 * 699 * @return This buffer 700 * 701 * @throws IndexOutOfBoundsException 702 * If {@code index} is negative 703 * or not smaller than the buffer's limit, 704 * minus three 705 * 706 * @throws ReadOnlyBufferException 707 * If this buffer is read-only 708 */ 709 abstract ByteBuffer putInt(int index, int value); 710 711 712 /** 713 * Relative <i>get</i> method for reading a long value. 714 * 715 * <p> Reads the next eight bytes at this buffer's current position, 716 * composing them into a long value according to the current byte order, 717 * and then increments the position by eight. </p> 718 * 719 * @return The long value at the buffer's current position 720 * 721 * @throws BufferUnderflowException 722 * If there are fewer than eight bytes 723 * remaining in this buffer 724 */ 725 abstract long getLong(); 726 727 /** 728 * Relative <i>put</i> method for writing a long 729 * value <i>(optional operation)</i>. 730 * 731 * <p> Writes eight bytes containing the given long value, in the 732 * current byte order, into this buffer at the current position, and then 733 * increments the position by eight. </p> 734 * 735 * @param value 736 * The long value to be written 737 * 738 * @return This buffer 739 * 740 * @throws BufferOverflowException 741 * If there are fewer than eight bytes 742 * remaining in this buffer 743 * 744 * @throws ReadOnlyBufferException 745 * If this buffer is read-only 746 */ 747 abstract ByteBuffer putLong(long value); 748 749 /** 750 * Absolute <i>get</i> method for reading a long value. 751 * 752 * <p> Reads eight bytes at the given index, composing them into a 753 * long value according to the current byte order. </p> 754 * 755 * @param index 756 * The index from which the bytes will be read 757 * 758 * @return The long value at the given index 759 * 760 * @throws IndexOutOfBoundsException 761 * If {@code index} is negative 762 * or not smaller than the buffer's limit, 763 * minus seven 764 */ 765 abstract long getLong(int index); 766 767 /** 768 * Absolute <i>put</i> method for writing a long 769 * value <i>(optional operation)</i>. 770 * 771 * <p> Writes eight bytes containing the given long value, in the 772 * current byte order, into this buffer at the given index. </p> 773 * 774 * @param index 775 * The index at which the bytes will be written 776 * 777 * @param value 778 * The long value to be written 779 * 780 * @return This buffer 781 * 782 * @throws IndexOutOfBoundsException 783 * If {@code index} is negative 784 * or not smaller than the buffer's limit, 785 * minus seven 786 * 787 * @throws ReadOnlyBufferException 788 * If this buffer is read-only 789 */ 790 abstract ByteBuffer putLong(int index, long value); 791 792 793 // -- Other stuff -- 794 795 /** 796 * Tells whether or not this buffer is backed by an accessible byte 797 * array. 798 * 799 * <p> If this method returns <tt>true</tt> then the {@link #array() array} 800 * and {@link #arrayOffset() arrayOffset} methods may safely be invoked. 801 * </p> 802 * 803 * @return <tt>true</tt> if, and only if, this buffer 804 * is backed by an array and is not read-only 805 */ 806 final override bool hasArray() { 807 return (hb !is null) && !isReadOnly; 808 } 809 810 /** 811 * Returns the byte array that backs this 812 * buffer <i>(optional operation)</i>. 813 * 814 * <p> Modifications to this buffer's content will cause the returned 815 * array's content to be modified, and vice versa. 816 * 817 * <p> Invoke the {@link #hasArray hasArray} method before invoking this 818 * method in order to ensure that this buffer has an accessible backing 819 * array. </p> 820 * 821 * @return The array that backs this buffer 822 * 823 * @throws ReadOnlyBufferException 824 * If this buffer is backed by an array but is read-only 825 * 826 * @throws UnsupportedOperationException 827 * If this buffer is not backed by an accessible array 828 */ 829 final byte[] array() { 830 if (hb is null) 831 throw new UnsupportedOperationException(""); 832 if (isReadOnly) 833 throw new ReadOnlyBufferException(""); 834 return hb; 835 } 836 837 /** 838 * Returns the offset within this buffer's backing array of the first 839 * element of the buffer <i>(optional operation)</i>. 840 * 841 * <p> If this buffer is backed by an array then buffer position <i>p</i> 842 * corresponds to array index <i>p</i> + <tt>arrayOffset()</tt>. 843 * 844 * <p> Invoke the {@link #hasArray hasArray} method before invoking this 845 * method in order to ensure that this buffer has an accessible backing 846 * array. </p> 847 * 848 * @return The offset within this buffer's array 849 * of the first element of the buffer 850 * 851 * @throws ReadOnlyBufferException 852 * If this buffer is backed by an array but is read-only 853 * 854 * @throws UnsupportedOperationException 855 * If this buffer is not backed by an accessible array 856 */ 857 final override int arrayOffset() { 858 if (hb is null) 859 throw new UnsupportedOperationException(""); 860 if (isReadOnly) 861 throw new ReadOnlyBufferException(""); 862 return offset; 863 } 864 865 /** 866 * Compacts this buffer <i>(optional operation)</i>. 867 * 868 * <p> The bytes between the buffer's current position and its limit, 869 * if any, are copied to the beginning of the buffer. That is, the 870 * byte at index <i>p</i> = <tt>position()</tt> is copied 871 * to index zero, the byte at index <i>p</i> + 1 is copied 872 * to index one, and so forth until the byte at index 873 * <tt>limit()</tt> - 1 is copied to index 874 * <i>n</i> = <tt>limit()</tt> - <tt>1</tt> - <i>p</i>. 875 * The buffer's position is then set to <i>n+1</i> and its limit is set to 876 * its capacity. The mark, if defined, is discarded. 877 * 878 * <p> The buffer's position is set to the number of bytes copied, 879 * rather than to zero, so that an invocation of this method can be 880 * followed immediately by an invocation of another relative <i>put</i> 881 * method. </p> 882 * 883 884 * 885 * <p> Invoke this method after writing data from a buffer in case the 886 * write was incomplete. The following loop, for example, copies bytes 887 * from one channel to another via the buffer <tt>buf</tt>: 888 * 889 * <blockquote><pre>{@code 890 * buf.clear(); // Prepare buffer for use 891 * while (in.read(buf) >= 0 || buf.position != 0) { 892 * buf.flip(); 893 * out.write(buf); 894 * buf.compact(); // In case of partial write 895 * } 896 * }</pre></blockquote> 897 * 898 899 * 900 * @return This buffer 901 * 902 * @throws ReadOnlyBufferException 903 * If this buffer is read-only 904 */ 905 abstract ByteBuffer compact(); 906 907 /** 908 * Tells whether or not this byte buffer is direct. 909 * 910 * @return <tt>true</tt> if, and only if, this buffer is direct 911 */ 912 // abstract bool isDirect(); 913 914 /** 915 * Relative <i>get</i> method for reading an int value. 916 * 917 * <p> Reads the next four bytes at this buffer's current position, 918 * composing them into an int value according to the current byte order, 919 * and then increments the position by four. </p> 920 * 921 * @return The int value at the buffer's current position 922 * 923 * @throws BufferUnderflowException 924 * If there are fewer than four bytes 925 * remaining in this buffer 926 */ 927 T get(T)() if (!is(T == byte)) { 928 enum len = T.sizeof; 929 int index = ix(nextGetIndex(len)); 930 ubyte[len] bytes = cast(ubyte[]) hb[index .. index + len]; 931 return bigEndianToNative!T(bytes); 932 } 933 934 /** 935 * Absolute <i>get</i> method for reading an int value. 936 * 937 * <p> Reads four bytes at the given index, composing them into a 938 * int value according to the current byte order. </p> 939 * 940 * @param index 941 * The index from which the bytes will be read 942 * 943 * @return The int value at the given index 944 * 945 * @throws IndexOutOfBoundsException 946 * If <tt>index</tt> is negative 947 * or not smaller than the buffer's limit, 948 * minus three 949 */ 950 T get(T)(int index) if (!is(T == byte)) { 951 enum len = T.sizeof; 952 int i = ix(checkIndex(index, len)); 953 ubyte[len] bytes = cast(ubyte[]) hb[i .. i + len]; 954 return bigEndianToNative!T(bytes); 955 } 956 957 /** 958 * Relative <i>put</i> method for writing a short 959 * value <i>(optional operation)</i>. 960 * 961 * <p> Writes two bytes containing the given short value, in the 962 * current byte order, into this buffer at the current position, and then 963 * increments the position by two. </p> 964 * 965 * @param value 966 * The short value to be written 967 * 968 * @return This buffer 969 * 970 * @throws BufferOverflowException 971 * If there are fewer than two bytes 972 * remaining in this buffer 973 * 974 * @throws ReadOnlyBufferException 975 * If this buffer is read-only 976 */ 977 ByteBuffer put(T)(T value) if (!is(T == byte)) { 978 enum len = T.sizeof; 979 int index = ix(nextPutIndex(len)); 980 ubyte[len] bytes = nativeToBigEndian(value); 981 hb[index .. index + len] = cast(byte[]) bytes[0 .. $]; 982 // byte* ptr = cast(byte*)&value; 983 // byte[] data = ptr[0..T.sizeof]; 984 // put(data, 0, cast(int)data.length); 985 return this; 986 } 987 988 /** 989 * Absolute <i>put</i> method for writing a short 990 * value <i>(optional operation)</i>. 991 * 992 * <p> Writes two bytes containing the given short value, in the 993 * current byte order, into this buffer at the given index. </p> 994 * 995 * @param index 996 * The index at which the bytes will be written 997 * 998 * @param value 999 * The short value to be written 1000 * 1001 * @return This buffer 1002 * 1003 * @throws IndexOutOfBoundsException 1004 * If <tt>index</tt> is negative 1005 * or not smaller than the buffer's limit, 1006 * minus one 1007 * 1008 * @throws ReadOnlyBufferException 1009 * If this buffer is read-only 1010 */ 1011 ByteBuffer put(T)(int index, T value) if (!is(T == byte)) { 1012 // byte* ptr = cast(byte*)&value; 1013 // byte[] data = ptr[0..T.sizeof]; 1014 // // put(data, 0, data.length); 1015 // for(int i=0; i<cast(int)data.length; i++) 1016 // put(index+i, data[i]); 1017 1018 enum len = T.sizeof; 1019 int i = ix(checkIndex(index, len)); 1020 ubyte[len] bytes = nativeToBigEndian(value); 1021 hb[i .. i + len] = cast(byte[]) bytes[0 .. $]; 1022 1023 return this; 1024 } 1025 1026 protected int ix(int i) { 1027 return i + offset; 1028 } 1029 1030 protected size_t byteOffset(size_t i) { 1031 return offset + i; 1032 } 1033 1034 string getString(size_t offset, size_t len) { 1035 return cast(string) hb[offset .. offset + len]; 1036 } 1037 1038 1039 byte[] getRemaining() { 1040 return hb[offset + position() .. offset + limit()]; 1041 } 1042 1043 /** 1044 * Returns a string summarizing the state of this buffer. 1045 * 1046 * @return A summary string 1047 */ 1048 override string toString() { 1049 StringBuffer sb = new StringBuffer(); 1050 // sb.append(getClass().getName()); 1051 sb.append("[pos="); 1052 sb.append(position()); 1053 sb.append(" lim="); 1054 sb.append(limit()); 1055 sb.append(" cap="); 1056 sb.append(capacity()); 1057 sb.append("]"); 1058 return sb.toString(); 1059 } 1060 1061 } 1062 1063 /** 1064 * A direct byte buffer whose content is a memory-mapped region of a file. 1065 * 1066 * <p> Mapped byte buffers are created via the {@link 1067 * java.nio.channels.FileChannel#map FileChannel.map} method. This class 1068 * : the {@link ByteBuffer} class with operations that are specific to 1069 * memory-mapped file regions. 1070 * 1071 * <p> A mapped byte buffer and the file mapping that it represents remain 1072 * valid until the buffer itself is garbage-collected. 1073 * 1074 * <p> The content of a mapped byte buffer can change at any time, for example 1075 * if the content of the corresponding region of the mapped file is changed by 1076 * this program or another. Whether or not such changes occur, and when they 1077 * occur, is operating-system dependent and therefore unspecified. 1078 * 1079 * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become 1080 * inaccessible at any time, for example if the mapped file is truncated. An 1081 * attempt to access an inaccessible region of a mapped byte buffer will not 1082 * change the buffer's content and will cause an unspecified exception to be 1083 * thrown either at the time of the access or at some later time. It is 1084 * therefore strongly recommended that appropriate precautions be taken to 1085 * avoid the manipulation of a mapped file by this program, or by a 1086 * concurrently running program, except to read or write the file's content. 1087 * 1088 * <p> Mapped byte buffers otherwise behave no differently than ordinary direct 1089 * byte buffers. </p> 1090 * 1091 * 1092 * @author Mark Reinhold 1093 * @author JSR-51 Expert Group 1094 */ 1095 // abstract class MappedByteBuffer : ByteBuffer 1096 // { 1097 1098 // // This is a little bit backwards: By rights MappedByteBuffer should be a 1099 // // subclass of DirectByteBuffer, but to keep the spec clear and simple, and 1100 // // for optimization purposes, it's easier to do it the other way around. 1101 // // This works because DirectByteBuffer is a package-private class. 1102 1103 // // For mapped buffers, a FileDescriptor that may be used for mapping 1104 // // operations if valid; null if the buffer is not mapped. 1105 // private FileDescriptor fd; 1106 1107 // // This should only be invoked by the DirectByteBuffer constructors 1108 // // 1109 // this(int mark, int pos, int lim, int cap, // package-private 1110 // FileDescriptor fd) 1111 // { 1112 // super(mark, pos, lim, cap); 1113 // this.fd = fd; 1114 // } 1115 1116 // this(int mark, int pos, int lim, int cap) { // package-private 1117 // super(mark, pos, lim, cap); 1118 // this.fd = null; 1119 // } 1120 1121 // private void checkMapped() { 1122 // if (fd is null) 1123 // // Can only happen if a luser explicitly casts a direct byte buffer 1124 // throw new UnsupportedOperationException(); 1125 // } 1126 1127 // // Returns the distance (in bytes) of the buffer from the page aligned address 1128 // // of the mapping. Computed each time to avoid storing in every direct buffer. 1129 // private long mappingOffset() { 1130 // int ps = Bits.pageSize(); 1131 // long offset = address % ps; 1132 // return (offset >= 0) ? offset : (ps + offset); 1133 // } 1134 1135 // private long mappingAddress(long mappingOffset) { 1136 // return address - mappingOffset; 1137 // } 1138 1139 // private long mappingLength(long mappingOffset) { 1140 // return (long)capacity() + mappingOffset; 1141 // } 1142 1143 // /** 1144 // * Tells whether or not this buffer's content is resident in physical 1145 // * memory. 1146 // * 1147 // * <p> A return value of <tt>true</tt> implies that it is highly likely 1148 // * that all of the data in this buffer is resident in physical memory and 1149 // * may therefore be accessed without incurring any virtual-memory page 1150 // * faults or I/O operations. A return value of <tt>false</tt> does not 1151 // * necessarily imply that the buffer's content is not resident in physical 1152 // * memory. 1153 // * 1154 // * <p> The returned value is a hint, rather than a guarantee, because the 1155 // * underlying operating system may have paged out some of the buffer's data 1156 // * by the time that an invocation of this method returns. </p> 1157 // * 1158 // * @return <tt>true</tt> if it is likely that this buffer's content 1159 // * is resident in physical memory 1160 // */ 1161 // final bool isLoaded() { 1162 // checkMapped(); 1163 // if ((address == 0) || (capacity() == 0)) 1164 // return true; 1165 // long offset = mappingOffset(); 1166 // long length = mappingLength(offset); 1167 // return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length)); 1168 // } 1169 1170 // // not used, but a potential target for a store, see load() for details. 1171 // private static byte unused; 1172 1173 // /** 1174 // * Loads this buffer's content into physical memory. 1175 // * 1176 // * <p> This method makes a best effort to ensure that, when it returns, 1177 // * this buffer's content is resident in physical memory. Invoking this 1178 // * method may cause some number of page faults and I/O operations to 1179 // * occur. </p> 1180 // * 1181 // * @return This buffer 1182 // */ 1183 // final MappedByteBuffer load() { 1184 // checkMapped(); 1185 // if ((address == 0) || (capacity() == 0)) 1186 // return this; 1187 // long offset = mappingOffset(); 1188 // long length = mappingLength(offset); 1189 // load0(mappingAddress(offset), length); 1190 1191 // // Read a byte from each page to bring it into memory. A checksum 1192 // // is computed as we go along to prevent the compiler from otherwise 1193 // // considering the loop as dead code. 1194 // Unsafe unsafe = Unsafe.getUnsafe(); 1195 // int ps = Bits.pageSize(); 1196 // int count = Bits.pageCount(length); 1197 // long a = mappingAddress(offset); 1198 // byte x = 0; 1199 // for (int i=0; i<count; i++) { 1200 // x ^= unsafe.getByte(a); 1201 // a += ps; 1202 // } 1203 // if (unused != 0) 1204 // unused = x; 1205 1206 // return this; 1207 // } 1208 1209 // /** 1210 // * Forces any changes made to this buffer's content to be written to the 1211 // * storage device containing the mapped file. 1212 // * 1213 // * <p> If the file mapped into this buffer resides on a local storage 1214 // * device then when this method returns it is guaranteed that all changes 1215 // * made to the buffer since it was created, or since this method was last 1216 // * invoked, will have been written to that device. 1217 // * 1218 // * <p> If the file does not reside on a local device then no such guarantee 1219 // * is made. 1220 // * 1221 // * <p> If this buffer was not mapped in read/write mode ({@link 1222 // * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this 1223 // * method has no effect. </p> 1224 // * 1225 // * @return This buffer 1226 // */ 1227 // final MappedByteBuffer force() { 1228 // checkMapped(); 1229 // if ((address != 0) && (capacity() != 0)) { 1230 // long offset = mappingOffset(); 1231 // force0(fd, mappingAddress(offset), mappingLength(offset)); 1232 // } 1233 // return this; 1234 // } 1235 1236 // private bool isLoaded0(long address, long length, int pageCount); 1237 // private void load0(long address, long length); 1238 // private void force0(FileDescriptor fd, long address, long length); 1239 // } 1240 1241 // interface DirectBuffer { 1242 1243 // long address(); 1244 1245 // Object attachment(); 1246 1247 // // Cleaner cleaner(); 1248 // }