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