1 module hunt.io.HeapByteBuffer;
2 
3 import hunt.io.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     private static long getLongUnaligned(byte[] buf, size_t offset) {
316         if ((offset & 7) == 0) {
317             return _getLong(buf, offset);
318         } else if ((offset & 3) == 0) {
319             return makeLong(_getInt(buf, offset),
320                             _getInt(buf, offset + 4));
321         } else if ((offset & 1) == 0) {
322             return makeLong(_getShort(buf, offset),
323                             _getShort(buf, offset + 2),
324                             _getShort(buf, offset + 4),
325                             _getShort(buf, offset + 6));
326         } else {
327             return makeLong(buf[offset],
328                             buf[offset + 1],
329                             buf[offset + 2],
330                             buf[offset + 3],
331                             buf[offset + 4],
332                             buf[offset + 5],
333                             buf[offset + 6],
334                             buf[offset + 7]);
335         }
336     }
337 
338     /**
339      * As {@link #getLongUnaligned(Object, long)} but with an
340      * additional argument which specifies the endianness of the value
341      * as stored in memory.
342      *
343      * @param o heap object in which the variable resides
344      * @param offset The offset in bytes from the start of the object
345      * @param bigEndian The endianness of the value
346      * @return the value fetched from the indicated object
347      */
348     private static long getLongUnaligned(byte[] hb,  size_t offset, bool bigEndian) {
349         return convEndian(bigEndian, getLongUnaligned(hb, offset));
350     }
351 
352     /**
353      * As {@link #putLongUnaligned(Object, long, long)} but with an additional
354      * argument which specifies the endianness of the value as stored in memory.
355      * @param o heap object in which the value resides
356      * @param offset The offset in bytes from the start of the object
357      * @param x the value to store
358      * @param bigEndian The endianness of the value
359      * @throws RuntimeException No defined exceptions are thrown, not even
360      *         {@link NullPointerException}
361      */
362     private static void putLongUnaligned(byte[] buf, size_t offset, long x, bool bigEndian) {
363         putLongUnaligned(buf, offset, convEndian(bigEndian, x));
364     }
365 
366     // These methods write integers to memory from smaller parts
367     // provided by their caller.  The ordering in which these parts
368     // are written is the native endianness of this platform.
369     private static void putLongParts(byte[] buf, size_t offset, byte i0, byte i1, byte i2, 
370         byte i3, byte i4, byte i5, byte i6, byte i7) {
371         buf[offset + 0] = pick(i0, i7);
372         buf[offset + 1] = pick(i1, i6);
373         buf[offset + 2] = pick(i2, i5);
374         buf[offset + 3] = pick(i3, i4);
375         buf[offset + 4] = pick(i4, i3);
376         buf[offset + 5] = pick(i5, i2);
377         buf[offset + 6] = pick(i6, i1);
378         buf[offset + 7] = pick(i7, i0);
379     }
380 
381     private static void putLongParts(byte[] buf, size_t offset, short i0, short i1, short i2, short i3) {
382         _putShort(buf, offset + 0, pick(i0, i3));
383         _putShort(buf, offset + 2, pick(i1, i2));
384         _putShort(buf, offset + 4, pick(i2, i1));
385         _putShort(buf, offset + 6, pick(i3, i0));
386     }
387 
388     private static void putLongParts(byte[] buf, size_t offset, int i0, int i1) {
389         _putInt(buf, offset + 0, pick(i0, i1));
390         _putInt(buf, offset + 4, pick(i1, i0));
391     }
392 
393     private static void putLongUnaligned(byte[] hb, size_t offset, long x) {
394         if ((offset & 7) == 0) {
395             _putLong(hb, offset, x);
396         } else if ((offset & 3) == 0) {
397             putLongParts(hb, offset,
398                          cast(int)(x >> 0),
399                          cast(int)(x >>> 32));
400         } else if ((offset & 1) == 0) {
401             putLongParts(hb, offset,
402                          cast(short)(x >>> 0),
403                          cast(short)(x >>> 16),
404                          cast(short)(x >>> 32),
405                          cast(short)(x >>> 48));
406         } else {
407             putLongParts(hb, offset,
408                          cast(byte)(x >>> 0),
409                          cast(byte)(x >>> 8),
410                          cast(byte)(x >>> 16),
411                          cast(byte)(x >>> 24),
412                          cast(byte)(x >>> 32),
413                          cast(byte)(x >>> 40),
414                          cast(byte)(x >>> 48),
415                          cast(byte)(x >>> 56));
416         }
417     }
418 
419     private static short _getShort(byte[] buf, size_t offset) {
420         short* ptr = cast(short*)(buf.ptr + offset);
421         return *ptr;
422     }
423 
424     private static void _putShort(byte[] buf, size_t offset, short x) {
425         buf[offset] = short0(x);
426         buf[offset + 1] = short1(x);
427     }
428 
429     private static int _getInt(byte[] buf, size_t offset) {
430         int* ptr = cast(int*)(buf.ptr + offset);
431         return *ptr;
432     }
433 
434     private static void _putInt(byte[] buf, size_t offset, int x) {
435         buf[offset] = int0(x);
436         buf[offset + 1] = int1(x);
437         buf[offset + 2] = int2(x);
438         buf[offset + 3] = int3(x);
439     }
440 
441     private static long _getLong(byte[] buf, size_t offset) {
442         long* ptr = cast(long*)(buf.ptr + offset);
443         return *ptr;
444     }
445 
446     private static void  _putLong(byte[] buf, size_t offset, long x) {
447         buf[offset] = long0(x);
448         buf[offset + 1] = long1(x);
449         buf[offset + 2] = long2(x);
450         buf[offset + 3] = long3(x);
451 
452         buf[offset + 4] = long4(x);
453         buf[offset + 5] = long5(x);
454         buf[offset + 6] = long6(x);
455         buf[offset + 7] = long7(x);
456     }
457 
458     private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
459         return ((toUnsignedLong(i0) << pickPos(56, 0))
460               | (toUnsignedLong(i1) << pickPos(56, 8))
461               | (toUnsignedLong(i2) << pickPos(56, 16))
462               | (toUnsignedLong(i3) << pickPos(56, 24))
463               | (toUnsignedLong(i4) << pickPos(56, 32))
464               | (toUnsignedLong(i5) << pickPos(56, 40))
465               | (toUnsignedLong(i6) << pickPos(56, 48))
466               | (toUnsignedLong(i7) << pickPos(56, 56)));
467     }
468 
469     private static long makeLong(short i0, short i1, short i2, short i3) {
470         return ((toUnsignedLong(i0) << pickPos(48, 0))
471               | (toUnsignedLong(i1) << pickPos(48, 16))
472               | (toUnsignedLong(i2) << pickPos(48, 32))
473               | (toUnsignedLong(i3) << pickPos(48, 48)));
474     }
475 
476     private static long makeLong(int i0, int i1) {
477         return (toUnsignedLong(i0) << pickPos(32, 0))
478              | (toUnsignedLong(i1) << pickPos(32, 32));
479     }
480 
481     private static int makeInt(short i0, short i1) {
482         return (toUnsignedInt(i0) << pickPos(16, 0))
483              | (toUnsignedInt(i1) << pickPos(16, 16));
484     }
485 
486     private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
487         return ((toUnsignedInt(i0) << pickPos(24, 0))
488               | (toUnsignedInt(i1) << pickPos(24, 8))
489               | (toUnsignedInt(i2) << pickPos(24, 16))
490               | (toUnsignedInt(i3) << pickPos(24, 24)));
491     }
492 
493     static short makeShort(byte i0, byte i1) {
494         return cast(short)((toUnsignedInt(i0) << pickPos(8, 0))
495                      | (toUnsignedInt(i1) << pickPos(8, 8)));
496     }
497 
498     private static short shortReverseBytes(short i) {
499         return cast(short) (((i & 0xFF00) >> 8) | (i << 8));
500     }
501 
502     private static int intReverseBytes(int i) {
503         return (i << 24)            |
504                ((i & 0xff00) << 8)  |
505                ((i >>> 8) & 0xff00) |
506                (i >>> 24);
507     }
508 
509     private static long longReverseBytes(long i) {
510         i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
511         return (i << 48) | ((i & 0xffff0000L) << 16) |
512             ((i >>> 16) & 0xffff0000L) | (i >>> 48);
513     }
514 
515     version (LittleEndian) {
516         // Maybe byte-reverse an integer
517         // private static char convEndian(bool big, char n)   { return big == BE ? n : Char.reverseBytes(n); }
518         private static short convEndian(bool big, short n) { return big ? shortReverseBytes(n) : n   ; }
519         private static int convEndian(bool big, int n)     { return big ? intReverseBytes(n) : n ; }
520         private static long convEndian(bool big, long n)   { return big ? longReverseBytes(n) : n    ; }
521 
522         private static byte  pick(byte  le, byte  be) { return le; }
523         private static short pick(short le, short be) { return le; }
524         private static int   pick(int   le, int   be) { return le; }
525 
526         private static int pickPos(int top, int pos) { return pos; }
527     } else {
528         // Maybe byte-reverse an integer
529         // private static char convEndian(bool big, char n)   { return big == BE ? n : Character.reverseBytes(n); }
530         private static short convEndian(bool big, short n) { return big ? n : shortReverseBytes(n)    ; }
531         private static int convEndian(bool big, int n)     { return big ? n : intReverseBytes(n)  ; }
532         private static long convEndian(bool big, long n)   { return big ? n : longReverseBytes(n)     ; }
533 
534         private static byte  pick(byte  le, byte  be) { return be; }
535         private static short pick(short le, short be) { return be; }
536         private static int   pick(int   le, int   be) { return be; }
537 
538         private static int pickPos(int top, int pos) { return top - pos; }
539     }
540 
541     // Zero-extend an integer
542     private static int toUnsignedInt(byte n)    { return n & 0xff; }
543     private static int toUnsignedInt(short n)   { return n & 0xffff; }
544     private static long toUnsignedLong(byte n)  { return n & 0xffL; }
545     private static long toUnsignedLong(short n) { return n & 0xffffL; }
546     private static long toUnsignedLong(int n)   { return n & 0xffffffffL; }
547 
548     // private static byte short1(short x) { return cast(byte)(x >> 8); }
549     // private static byte short0(short x) { return cast(byte)(x     ); }
550 
551     private static byte int3(int x) { return cast(byte)(x >> 24); }
552     private static byte int2(int x) { return cast(byte)(x >> 16); }
553     private static byte int1(int x) { return cast(byte)(x >>  8); }
554     private static byte int0(int x) { return cast(byte)(x      ); }
555 
556     private static byte long7(long x) { return cast(byte)(x >> 56); }
557     private static byte long6(long x) { return cast(byte)(x >> 48); }
558     private static byte long5(long x) { return cast(byte)(x >> 40); }
559     private static byte long4(long x) { return cast(byte)(x >> 32); }
560     private static byte long3(long x) { return cast(byte)(x >> 24); }
561     private static byte long2(long x) { return cast(byte)(x >> 16); }
562     private static byte long1(long x) { return cast(byte)(x >>  8); }
563     private static byte long0(long x) { return cast(byte)(x      ); }
564 
565     // dfmt on
566 
567     override ByteBuffer compact() {
568         int sourceIndex = ix(position());
569         int targetIndex = ix(0);
570         int len = remaining();
571         // tracef("hb.length=%d, remaining=%d, targetIndex=%d, sourceIndex=%d", hb.length, len, targetIndex, sourceIndex) ;
572         if(targetIndex != sourceIndex) {
573             hb[targetIndex .. targetIndex + len] = hb[sourceIndex .. sourceIndex + len];
574             position(len);
575             limit(capacity());
576             discardMark();
577         }
578         return this;
579 
580     }
581 }