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