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&nbsp;&nbsp;<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&nbsp;&nbsp;<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>&nbsp;<tt>&gt;</tt>&nbsp;<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,&nbsp;off,&nbsp;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&nbsp;&nbsp;<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>&nbsp;<tt>&gt;</tt>&nbsp;<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>&nbsp;=&nbsp;<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&nbsp;&nbsp;<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>&nbsp;<tt>&gt;</tt>&nbsp;<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,&nbsp;off,&nbsp;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&nbsp;&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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>&nbsp;+&nbsp;<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&nbsp;&nbsp;<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>&nbsp;=&nbsp;<tt>position()</tt> is copied
805      * to index zero, the byte at index <i>p</i>&nbsp;+&nbsp;1 is copied
806      * to index one, and so forth until the byte at index
807      * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
808      * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<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&nbsp;&nbsp;<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&nbsp;&nbsp;<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