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