1 module hunt.collection.HeapByteBuffer;
2 
3 import hunt.collection.ByteBuffer;
4 import hunt.Exceptions;
5 
6 import hunt.Integer;
7 import hunt.Long;
8 import hunt.Short;
9 
10 import std.format;
11 
12 /**
13 */
14 class HeapByteBuffer : ByteBuffer {
15 
16     // For speed these fields are actually declared in X-Buffer;
17     // these declarations are here as documentation
18 
19     this(int cap, int lim) { // package-private
20 
21         super(-1, 0, lim, cap, new byte[cap], 0);
22         /*
23         hb = new byte[cap];
24         offset = 0;
25         */
26     }
27 
28     this(byte[] buf, int off, int len) { // package-private
29 
30         super(-1, off, off + len, cast(int) buf.length, buf, 0);
31         /*
32         hb = buf;
33         offset = 0;
34         */
35     }
36 
37     protected this(byte[] buf, int mark, int pos, int lim, int cap, int off) {
38 
39         super(mark, pos, lim, cap, buf, off);
40         /*
41         hb = buf;
42         offset = off;
43         */
44 
45     }
46 
47     override ByteBuffer slice() {
48         return new HeapByteBuffer(hb, -1, 0, this.remaining(),
49                 this.remaining(), this.position() + offset);
50     }
51 
52     override ByteBuffer duplicate() {
53         return new HeapByteBuffer(hb, this.markValue(), this.position(),
54                 this.limit(), this.capacity(), offset);
55     }
56 
57     override ByteBuffer asReadOnlyBuffer() {
58         return new HeapByteBuffer(hb, this.markValue(), this.position(),
59                 this.limit(), this.capacity(), offset);
60     }
61 
62     override byte get() {
63         return hb[ix(nextGetIndex())];
64     }
65 
66     override byte get(int i) {
67         return hb[ix(checkIndex(i))];
68     }
69 
70     override ByteBuffer get(byte[] dst, int offset, int length) {
71         checkBounds(offset, length, cast(int) dst.length);
72         if (length > remaining())
73             throw new BufferUnderflowException("");
74         // System.arraycopy(hb, ix(position()), dst, offset, length);
75         int sourcePos = ix(position());
76         dst[offset .. offset + length] = hb[sourcePos .. sourcePos + length];
77         position(position() + length);
78         return this;
79     }
80 
81     override bool isDirect() {
82         return false;
83     }
84 
85     override bool isReadOnly() {
86         return false;
87     }
88 
89     override ByteBuffer put(byte x) {
90 
91         hb[ix(nextPutIndex())] = x;
92         return this;
93 
94     }
95 
96     override ByteBuffer put(int i, byte x) {
97         hb[ix(checkIndex(i))] = x;
98         return this;
99     }
100 
101     override ByteBuffer put(byte[] src, int offset, int length) {
102 
103         checkBounds(offset, length, cast(int) src.length);
104 
105         if (length > remaining())
106             throw new BufferOverflowException();
107         int newPos = ix(position());
108         hb[newPos .. newPos + length] = src[offset .. offset + length];
109 
110         position(position() + length);
111         return this;
112 
113     }
114 
115     override ByteBuffer put(ByteBuffer src) {
116         if (typeid(src) == typeid(HeapByteBuffer)) {
117             if (src is this)
118                 throw new IllegalArgumentException();
119             HeapByteBuffer sb = cast(HeapByteBuffer) src;
120             int n = sb.remaining();
121             int r = this.remaining();
122             if (n > r)
123                 throw new BufferOverflowException(format("soure remaining: %d, this remaining: %d", n, r));
124 
125             int sourcePos = sb.ix(sb.position());
126             int targetPos = ix(position());
127             hb[targetPos .. targetPos + n] = sb.hb[sourcePos .. sourcePos + n];
128 
129             sb.position(sb.position() + n);
130             position(position() + n);
131         } else if (src.isDirect()) {
132             int n = src.remaining();
133             if (n > remaining())
134                 throw new BufferOverflowException("");
135             src.get(hb, ix(position()), n);
136             position(position() + n);
137         } else {
138             super.put(src);
139         }
140         return this;
141 
142     }
143 
144     // short
145 
146     private static byte short1(short x) {
147         return cast(byte)(x >> 8);
148     }
149 
150     private static byte short0(short x) {
151         return cast(byte)(x);
152     }
153 
154     override short getShort() {
155         int index = ix(nextGetIndex(2));
156         // short r = 0;
157         // short* ptr = &r;
158         // ptr[0]=hb[index+1]; // bigEndian
159         // ptr[1]=hb[index]; 
160         // if (bigEndian)
161         //     return makeShort(hb[index], hb[index + 1]);
162         // else
163         //     return makeShort(hb[index + 1], hb[index]);
164 
165         return convEndian(bigEndian, makeShort(hb[index], hb[index + 1]));
166     }
167 
168     override short getShort(int i) {
169         int index = ix(checkIndex(i, 2));
170         return convEndian(bigEndian, makeShort(hb[index], hb[index + 1]));
171         // if (bigEndian)
172         //     return makeShort(hb[index], hb[index + 1]);
173         // else
174         //     return makeShort(hb[index + 1], hb[index]);
175     }
176 
177     override ByteBuffer putShort(short x) {
178         int index = ix(nextPutIndex(2));
179         if (bigEndian) {
180             hb[index] = short1(x);
181             hb[index + 1] = short0(x);
182         } else {
183             hb[index] = short0(x);
184             hb[index + 1] = short1(x);
185         }
186 
187         return this;
188     }
189 
190     override ByteBuffer putShort(int i, short x) {
191         int index = ix(checkIndex(i, 2));
192         if (bigEndian) {
193             hb[index] = short1(x);
194             hb[index + 1] = short0(x);
195         } else {
196             hb[index] = short0(x);
197             hb[index + 1] = short1(x);
198         }
199         return this;
200     }
201 
202     // int
203     override int getInt() {
204         // auto index = ix(nextGetIndex(4));
205         // return _getInt(index);
206         return getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
207     }
208 
209     override int getInt(int i) {
210         // auto index = ix(checkIndex(i, 4));
211         // return _getInt(index);
212         return getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
213     }
214 
215     // private int _getInt(size_t index) {
216     //     if (bigEndian)
217     //         return makeInt(hb[index], hb[index + 1], hb[index + 2], hb[index + 3]);
218     //     else
219     //         return makeInt(hb[index + 3], hb[index + 2], hb[index + 1], hb[index]);
220     // }
221 
222     // private static int makeInt(byte b3, byte b2, byte b1, byte b0) {
223     //     return ((b3) << 24) | ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | (b0 & 0xff);
224     // }
225 
226     override ByteBuffer putInt(int x) {
227         putIntUnaligned(hb, ix(nextPutIndex(4)), x, bigEndian);
228         return this;
229     }
230 
231     override ByteBuffer putInt(int i, int x) {
232         putIntUnaligned(hb, ix(checkIndex(i, 4)), x, bigEndian);
233         return this;
234     }
235 
236     // long
237 
238     override long getLong() {
239         return getLongUnaligned(hb, ix(nextGetIndex(8)), bigEndian);
240     }
241 
242     override long getLong(int i) {
243         return getLongUnaligned(hb, ix(checkIndex(i, 8)), bigEndian);
244     }
245 
246     override ByteBuffer putLong(long x) {
247         putLongUnaligned(hb, ix(nextPutIndex(8)), x, bigEndian);
248         return this;
249     }
250 
251     override ByteBuffer putLong(int i, long x) {
252         putLongUnaligned(hb, ix(checkIndex(i, 8)), x, bigEndian);
253         return this;
254     }
255 
256     // dfmt off
257 
258 
259     private static void putShortParts(byte[] buf, size_t offset, byte i0, byte i1) {
260         buf[offset + 0] = pick(i0, i1);
261         buf[offset + 1] = pick(i1, i0);
262     }
263 
264     private static void putIntParts(byte[] buf, size_t offset, short i0, short i1) {
265         _putShort(buf, offset + 0, pick(i0, i1));
266         _putShort(buf, offset + 2, pick(i1, i0));
267     }
268 
269     private static void putIntParts(byte[] buf, size_t offset, byte i0, byte i1, byte i2, byte i3) {
270         buf[offset + 0] = pick(i0, i3);
271         buf[offset + 1] = pick(i1, i2);
272         buf[offset + 2] = pick(i2, i1);
273         buf[offset + 3] = pick(i3, i0);
274     }
275     
276     private static void putIntUnaligned(byte[] buf, size_t offset, int x) {
277         if ((offset & 3) == 0) {
278             _putInt(buf, offset, x);
279         } else if ((offset & 1) == 0) {
280             putIntParts(buf, offset,
281                         cast(short)(x >> 0),
282                         cast(short)(x >>> 16));
283         } else {
284             putIntParts(buf, offset,
285                         cast(byte)(x >>> 0),
286                         cast(byte)(x >>> 8),
287                         cast(byte)(x >>> 16),
288                         cast(byte)(x >>> 24));
289         }
290     }
291 
292     private static void putIntUnaligned(byte[] buf, size_t offset, int x, bool bigEndian) {
293         putIntUnaligned(buf, offset, convEndian(bigEndian, x));
294     }
295 
296 
297     private static int getIntUnaligned(byte[] buf, size_t offset) {
298         if ((offset & 3) == 0) {
299             return _getInt(buf, offset);
300         } else if ((offset & 1) == 0) {
301             return makeInt(_getShort(buf, offset),
302                            _getShort(buf, offset + 2));
303         } else {
304             return makeInt(buf[offset],
305                            buf[offset + 1],
306                            buf[offset + 2],
307                            buf[offset + 3]);
308         }
309     }
310 
311     private static int getIntUnaligned(byte[] buf, size_t offset, bool bigEndian) {
312         return convEndian(bigEndian, getIntUnaligned(buf, offset));
313     }    
314 
315     /**
316      * Fetches a value at some byte offset into a given Java object.
317      * More specifically, fetches a value within the given object
318      * <code>o</code> at the given offset, or (if <code>o</code> is
319      * null) from the memory address whose numerical value is the
320      * given offset.  <p>
321      *
322      * The specification of this method is the same as {@link
323      * #getLong(Object, long)} except that the offset does not need to
324      * have been obtained from {@link #objectFieldOffset} on the
325      * {@link java.lang.reflect.Field} of some Java field.  The value
326      * in memory is raw data, and need not correspond to any Java
327      * variable.  Unless <code>o</code> is null, the value accessed
328      * must be entirely within the allocated object.  The endianness
329      * of the value in memory is the endianness of the native platform.
330      *
331      * <p> The read will be atomic with respect to the largest power
332      * of two that divides the GCD of the offset and the storage size.
333      * For example, getLongUnaligned will make atomic reads of 2-, 4-,
334      * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
335      * respectively.  There are no other guarantees of atomicity.
336      * <p>
337      * 8-byte atomicity is only guaranteed on platforms on which
338      * support atomic accesses to longs.
339      *
340      * @param o Java heap object in which the value resides, if any, else
341      *        null
342      * @param offset The offset in bytes from the start of the object
343      * @return the value fetched from the indicated object
344      * @throws RuntimeException No defined exceptions are thrown, not even
345      *         {@link NullPointerException}
346      */
347     private static long getLongUnaligned(byte[] buf, size_t offset) {
348         if ((offset & 7) == 0) {
349             return _getLong(buf, offset);
350         } else if ((offset & 3) == 0) {
351             return makeLong(_getInt(buf, offset),
352                             _getInt(buf, offset + 4));
353         } else if ((offset & 1) == 0) {
354             return makeLong(_getShort(buf, offset),
355                             _getShort(buf, offset + 2),
356                             _getShort(buf, offset + 4),
357                             _getShort(buf, offset + 6));
358         } else {
359             return makeLong(buf[offset],
360                             buf[offset + 1],
361                             buf[offset + 2],
362                             buf[offset + 3],
363                             buf[offset + 4],
364                             buf[offset + 5],
365                             buf[offset + 6],
366                             buf[offset + 7]);
367         }
368     }
369 
370     /**
371      * As {@link #getLongUnaligned(Object, long)} but with an
372      * additional argument which specifies the endianness of the value
373      * as stored in memory.
374      *
375      * @param o Java heap object in which the variable resides
376      * @param offset The offset in bytes from the start of the object
377      * @param bigEndian The endianness of the value
378      * @return the value fetched from the indicated object
379      */
380     private static long getLongUnaligned(byte[] hb,  size_t offset, bool bigEndian) {
381         return convEndian(bigEndian, getLongUnaligned(hb, offset));
382     }
383 
384     /**
385      * As {@link #putLongUnaligned(Object, long, long)} but with an additional
386      * argument which specifies the endianness of the value as stored in memory.
387      * @param o Java heap object in which the value resides
388      * @param offset The offset in bytes from the start of the object
389      * @param x the value to store
390      * @param bigEndian The endianness of the value
391      * @throws RuntimeException No defined exceptions are thrown, not even
392      *         {@link NullPointerException}
393      */
394     private static void putLongUnaligned(byte[] buf, size_t offset, long x, bool bigEndian) {
395         putLongUnaligned(buf, offset, convEndian(bigEndian, x));
396     }
397 
398     // These methods write integers to memory from smaller parts
399     // provided by their caller.  The ordering in which these parts
400     // are written is the native endianness of this platform.
401     private static void putLongParts(byte[] buf, size_t offset, byte i0, byte i1, byte i2, 
402         byte i3, byte i4, byte i5, byte i6, byte i7) {
403         buf[offset + 0] = pick(i0, i7);
404         buf[offset + 1] = pick(i1, i6);
405         buf[offset + 2] = pick(i2, i5);
406         buf[offset + 3] = pick(i3, i4);
407         buf[offset + 4] = pick(i4, i3);
408         buf[offset + 5] = pick(i5, i2);
409         buf[offset + 6] = pick(i6, i1);
410         buf[offset + 7] = pick(i7, i0);
411     }
412 
413     private static void putLongParts(byte[] buf, size_t offset, short i0, short i1, short i2, short i3) {
414         _putShort(buf, offset + 0, pick(i0, i3));
415         _putShort(buf, offset + 2, pick(i1, i2));
416         _putShort(buf, offset + 4, pick(i2, i1));
417         _putShort(buf, offset + 6, pick(i3, i0));
418     }
419 
420     private static void putLongParts(byte[] buf, size_t offset, int i0, int i1) {
421         _putInt(buf, offset + 0, pick(i0, i1));
422         _putInt(buf, offset + 4, pick(i1, i0));
423     }
424 
425     private static void putLongUnaligned(byte[] hb, size_t offset, long x) {
426         if ((offset & 7) == 0) {
427             _putLong(hb, offset, x);
428         } else if ((offset & 3) == 0) {
429             putLongParts(hb, offset,
430                          cast(int)(x >> 0),
431                          cast(int)(x >>> 32));
432         } else if ((offset & 1) == 0) {
433             putLongParts(hb, offset,
434                          cast(short)(x >>> 0),
435                          cast(short)(x >>> 16),
436                          cast(short)(x >>> 32),
437                          cast(short)(x >>> 48));
438         } else {
439             putLongParts(hb, offset,
440                          cast(byte)(x >>> 0),
441                          cast(byte)(x >>> 8),
442                          cast(byte)(x >>> 16),
443                          cast(byte)(x >>> 24),
444                          cast(byte)(x >>> 32),
445                          cast(byte)(x >>> 40),
446                          cast(byte)(x >>> 48),
447                          cast(byte)(x >>> 56));
448         }
449     }
450 
451     private static short _getShort(byte[] buf, size_t offset) {
452         short* ptr = cast(short*)(buf.ptr + offset);
453         return *ptr;
454     }
455 
456     private static void _putShort(byte[] buf, size_t offset, short x) {
457         buf[offset] = short0(x);
458         buf[offset + 1] = short1(x);
459     }
460 
461     private static int _getInt(byte[] buf, size_t offset) {
462         int* ptr = cast(int*)(buf.ptr + offset);
463         return *ptr;
464     }
465 
466     private static void _putInt(byte[] buf, size_t offset, int x) {
467         buf[offset] = int0(x);
468         buf[offset + 1] = int1(x);
469         buf[offset + 2] = int2(x);
470         buf[offset + 3] = int3(x);
471     }
472 
473     private static long _getLong(byte[] buf, size_t offset) {
474         long* ptr = cast(long*)(buf.ptr + offset);
475         return *ptr;
476     }
477 
478     private static void  _putLong(byte[] buf, size_t offset, long x) {
479         buf[offset] = long0(x);
480         buf[offset + 1] = long1(x);
481         buf[offset + 2] = long2(x);
482         buf[offset + 3] = long3(x);
483 
484         buf[offset + 4] = long4(x);
485         buf[offset + 5] = long5(x);
486         buf[offset + 6] = long6(x);
487         buf[offset + 7] = long7(x);
488     }
489 
490     private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
491         return ((toUnsignedLong(i0) << pickPos(56, 0))
492               | (toUnsignedLong(i1) << pickPos(56, 8))
493               | (toUnsignedLong(i2) << pickPos(56, 16))
494               | (toUnsignedLong(i3) << pickPos(56, 24))
495               | (toUnsignedLong(i4) << pickPos(56, 32))
496               | (toUnsignedLong(i5) << pickPos(56, 40))
497               | (toUnsignedLong(i6) << pickPos(56, 48))
498               | (toUnsignedLong(i7) << pickPos(56, 56)));
499     }
500 
501     private static long makeLong(short i0, short i1, short i2, short i3) {
502         return ((toUnsignedLong(i0) << pickPos(48, 0))
503               | (toUnsignedLong(i1) << pickPos(48, 16))
504               | (toUnsignedLong(i2) << pickPos(48, 32))
505               | (toUnsignedLong(i3) << pickPos(48, 48)));
506     }
507 
508     private static long makeLong(int i0, int i1) {
509         return (toUnsignedLong(i0) << pickPos(32, 0))
510              | (toUnsignedLong(i1) << pickPos(32, 32));
511     }
512 
513     private static int makeInt(short i0, short i1) {
514         return (toUnsignedInt(i0) << pickPos(16, 0))
515              | (toUnsignedInt(i1) << pickPos(16, 16));
516     }
517 
518     private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
519         return ((toUnsignedInt(i0) << pickPos(24, 0))
520               | (toUnsignedInt(i1) << pickPos(24, 8))
521               | (toUnsignedInt(i2) << pickPos(24, 16))
522               | (toUnsignedInt(i3) << pickPos(24, 24)));
523     }
524 
525     static short makeShort(byte i0, byte i1) {
526         return cast(short)((toUnsignedInt(i0) << pickPos(8, 0))
527                      | (toUnsignedInt(i1) << pickPos(8, 8)));
528     }
529 
530     version (LittleEndian) {
531         // Maybe byte-reverse an integer
532         // private static char convEndian(bool big, char n)   { return big == BE ? n : Char.reverseBytes(n); }
533         private static short convEndian(bool big, short n) { return big ? Short.reverseBytes(n) : n   ; }
534         private static int convEndian(bool big, int n)     { return big ? Integer.reverseBytes(n) : n ; }
535         private static long convEndian(bool big, long n)   { return big ? Long.reverseBytes(n) : n    ; }
536 
537         private static byte  pick(byte  le, byte  be) { return le; }
538         private static short pick(short le, short be) { return le; }
539         private static int   pick(int   le, int   be) { return le; }
540 
541         private static int pickPos(int top, int pos) { return pos; }
542     } else {
543         // Maybe byte-reverse an integer
544         // private static char convEndian(bool big, char n)   { return big == BE ? n : Character.reverseBytes(n); }
545         private static short convEndian(bool big, short n) { return big ? n : Short.reverseBytes(n)    ; }
546         private static int convEndian(bool big, int n)     { return big ? n : Integer.reverseBytes(n)  ; }
547         private static long convEndian(bool big, long n)   { return big ? n : Long.reverseBytes(n)     ; }
548 
549         private static byte  pick(byte  le, byte  be) { return be; }
550         private static short pick(short le, short be) { return be; }
551         private static int   pick(int   le, int   be) { return be; }
552 
553         private static int pickPos(int top, int pos) { return top - pos; }
554     }
555 
556     // Zero-extend an integer
557     private static int toUnsignedInt(byte n)    { return n & 0xff; }
558     private static int toUnsignedInt(short n)   { return n & 0xffff; }
559     private static long toUnsignedLong(byte n)  { return n & 0xffL; }
560     private static long toUnsignedLong(short n) { return n & 0xffffL; }
561     private static long toUnsignedLong(int n)   { return n & 0xffffffffL; }
562 
563     // private static byte short1(short x) { return cast(byte)(x >> 8); }
564     // private static byte short0(short x) { return cast(byte)(x     ); }
565 
566     private static byte int3(int x) { return cast(byte)(x >> 24); }
567     private static byte int2(int x) { return cast(byte)(x >> 16); }
568     private static byte int1(int x) { return cast(byte)(x >>  8); }
569     private static byte int0(int x) { return cast(byte)(x      ); }
570 
571     private static byte long7(long x) { return cast(byte)(x >> 56); }
572     private static byte long6(long x) { return cast(byte)(x >> 48); }
573     private static byte long5(long x) { return cast(byte)(x >> 40); }
574     private static byte long4(long x) { return cast(byte)(x >> 32); }
575     private static byte long3(long x) { return cast(byte)(x >> 24); }
576     private static byte long2(long x) { return cast(byte)(x >> 16); }
577     private static byte long1(long x) { return cast(byte)(x >>  8); }
578     private static byte long0(long x) { return cast(byte)(x      ); }
579 
580     // dfmt on
581 
582     override ByteBuffer compact() {
583         int sourceIndex = ix(position());
584         int targetIndex = ix(0);
585         int len = remaining();
586         // tracef("hb.length=%d, remaining=%d, targetIndex=%d, sourceIndex=%d", hb.length, len, targetIndex, sourceIndex) ;
587         if(targetIndex != sourceIndex) {
588             hb[targetIndex .. targetIndex + len] = hb[sourceIndex .. sourceIndex + len];
589             position(len);
590             limit(capacity());
591             discardMark();
592         }
593         return this;
594 
595     }
596 }