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