1 /*
2  * hunt-proton: AMQP Protocol 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.proton.codec.ArrayType;
13 
14 /*
15 import java.lang.reflect.Array;
16 import java.util.Arrays;
17 import hunt.collection.Collection;
18 
19 class ArrayType implements PrimitiveType!(Object[])
20 {
21     private EncoderImpl _encoder;
22     private BooleanType _boolType;
23     private ByteType _byteType;
24     private ShortType _shortType;
25     private IntegerType _integerType;
26     private LongType _longType;
27     private FloatType _floatType;
28     private DoubleType _doubleType;
29     private CharacterType _characterType;
30 
31     public static interface ArrayEncoding : PrimitiveTypeEncoding!(Object[])
32     {
33         void writeValue(bool[] a);
34         void writeValue(byte[] a);
35         void writeValue(short[] a);
36         void writeValue(int[] a);
37         void writeValue(long[] a);
38         void writeValue(float[] a);
39         void writeValue(double[] a);
40         void writeValue(char[] a);
41 
42         void setValue(Object[] val, TypeEncoding<?> encoder, int size);
43 
44         int getSizeBytes();
45 
46         Object readValueArray();
47     }
48 
49     private ArrayEncoding _shortArrayEncoding;
50     private ArrayEncoding _arrayEncoding;
51 
52     public ArrayType(EncoderImpl encoder,
53                      DecoderImpl decoder, BooleanType boolType,
54                      ByteType byteType,
55                      ShortType shortType,
56                      IntegerType intType,
57                      LongType longType,
58                      FloatType floatType,
59                      DoubleType doubleType,
60                      CharacterType characterType)
61     {
62         _encoder = encoder;
63         _boolType = boolType;
64         _byteType = byteType;
65         _shortType = shortType;
66         _integerType = intType;
67         _longType = longType;
68         _floatType = floatType;
69         _doubleType = doubleType;
70         _characterType = characterType;
71 
72         _arrayEncoding = new AllArrayEncoding(encoder, decoder);
73         _shortArrayEncoding = new ShortArrayEncoding(encoder, decoder);
74 
75         encoder.register(Object[].class, this);
76         decoder.register(this);
77     }
78 
79     override
80     public Class!(Object[]) getTypeClass()
81     {
82         return Object[].class;
83     }
84 
85     override
86     public ArrayEncoding getEncoding(Object[] val)
87     {
88         TypeEncoding<?> encoder = calculateEncoder(val,_encoder);
89         int size = calculateSize(val, encoder);
90         ArrayEncoding arrayEncoding = (val.length > 255 || size > 254)
91                                       ? _arrayEncoding
92                                       : _shortArrayEncoding;
93         arrayEncoding.setValue(val, encoder, size);
94         return arrayEncoding;
95     }
96 
97     private static TypeEncoding<?> calculateEncoder(Object[] val, EncoderImpl encoder)
98     {
99         if(val.length == 0)
100         {
101             AMQPType underlyingType = encoder.getTypeFromClass(val.getClass().getComponentType());
102             return underlyingType.getCanonicalEncoding();
103         }
104         else
105         {
106             AMQPType underlyingType = encoder.getTypeFromClass(val.getClass().getComponentType());
107             bool checkTypes = false;
108 
109             if(val[0].getClass().isArray() && val[0].getClass().getComponentType().isPrimitive())
110             {
111                 Class componentType = val[0].getClass().getComponentType();
112                 if(componentType == Boolean.TYPE)
113                 {
114                     return ((ArrayType)underlyingType).getEncoding((bool[])val[0]);
115                 }
116                 else if(componentType == Byte.TYPE)
117                 {
118                     return ((ArrayType)underlyingType).getEncoding((byte[])val[0]);
119                 }
120                 else if(componentType == Short.TYPE)
121                 {
122                     return ((ArrayType)underlyingType).getEncoding((short[])val[0]);
123                 }
124                 else if(componentType == Integer.TYPE)
125                 {
126                     return ((ArrayType)underlyingType).getEncoding((int[])val[0]);
127                 }
128                 else if(componentType == Long.TYPE)
129                 {
130                     return ((ArrayType)underlyingType).getEncoding((long[])val[0]);
131                 }
132                 else if(componentType == Float.TYPE)
133                 {
134                     return ((ArrayType)underlyingType).getEncoding((float[])val[0]);
135                 }
136                 else if(componentType == Double.TYPE)
137                 {
138                     return ((ArrayType)underlyingType).getEncoding((double[])val[0]);
139                 }
140                 else if(componentType == Character.TYPE)
141                 {
142                     return ((ArrayType)underlyingType).getEncoding((char[])val[0]);
143                 }
144                 else
145                 {
146                     throw new IllegalArgumentException("Cannot encode arrays of type " ~ componentType.getName());
147                 }
148             }
149             else
150             {
151                 if(underlyingType is null)
152                 {
153                     checkTypes = true;
154                     underlyingType = encoder.getType(val[0]);
155                 }
156                 TypeEncoding underlyingEncoding = underlyingType.getEncoding(val[0]);
157                 TypeEncoding canonicalEncoding = underlyingType.getCanonicalEncoding();
158 
159                 for(int i = 0; i < val.length && (checkTypes || underlyingEncoding != canonicalEncoding); i++)
160                 {
161                     if(checkTypes && encoder.getType(val[i]) != underlyingType)
162                     {
163                         throw new IllegalArgumentException("Non matching types " ~ underlyingType ~ " and " ~ encoder
164                                 .getType(val[i]) ~ " in array");
165                     }
166 
167                     TypeEncoding elementEncoding = underlyingType.getEncoding(val[i]);
168                     if(elementEncoding != underlyingEncoding && !underlyingEncoding.encodesSuperset(elementEncoding))
169                     {
170                         if(elementEncoding.encodesSuperset(underlyingEncoding))
171                         {
172                             underlyingEncoding = elementEncoding;
173                         }
174                         else
175                         {
176                             underlyingEncoding = canonicalEncoding;
177                         }
178                     }
179 
180                 }
181 
182                 return underlyingEncoding;
183             }
184         }
185     }
186 
187     private static int calculateSize(Object[] val, TypeEncoding encoder)
188     {
189         int size = encoder.getConstructorSize();
190         if(encoder.isFixedSizeVal())
191         {
192             size += val.length * encoder.getValueSize(null);
193         }
194         else
195         {
196             for(Object o : val)
197             {
198                 if(o.getClass().isArray() && o.getClass().getComponentType().isPrimitive())
199                 {
200                     ArrayEncoding arrayEncoding = (ArrayEncoding) encoder;
201                     ArrayType arrayType = (ArrayType) arrayEncoding.getType();
202 
203                     Class componentType = o.getClass().getComponentType();
204 
205                     size += 2 * arrayEncoding.getSizeBytes();
206 
207                     TypeEncoding componentEncoding;
208                     int componentCount;
209 
210                     if(componentType == Boolean.TYPE)
211                     {
212                         bool[] componentArray = (bool[]) o;
213                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
214                         componentCount = componentArray.length;
215                     }
216                     else if(componentType == Byte.TYPE)
217                     {
218                         byte[] componentArray = (byte[]) o;
219                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
220                         componentCount = componentArray.length;
221                     }
222                     else if(componentType == Short.TYPE)
223                     {
224                         short[] componentArray = (short[]) o;
225                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
226                         componentCount = componentArray.length;
227                     }
228                     else if(componentType == Integer.TYPE)
229                     {
230                         int[] componentArray = (int[]) o;
231                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
232                         componentCount = componentArray.length;
233                     }
234                     else if(componentType == Long.TYPE)
235                     {
236                         long[] componentArray = (long[]) o;
237                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
238                         componentCount = componentArray.length;
239                     }
240                     else if(componentType == Float.TYPE)
241                     {
242                         float[] componentArray = (float[]) o;
243                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
244                         componentCount = componentArray.length;
245                     }
246                     else if(componentType == Double.TYPE)
247                     {
248                         double[] componentArray = (double[]) o;
249                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
250                         componentCount = componentArray.length;
251                     }
252                     else if(componentType == Character.TYPE)
253                     {
254                         char[] componentArray = (char[]) o;
255                         componentEncoding = arrayType.getUnderlyingEncoding(componentArray);
256                         componentCount = componentArray.length;
257                     }
258                     else
259                     {
260                         throw new IllegalArgumentException("Cannot encode arrays of type " ~ componentType.getName());
261                     }
262 
263                     size +=  componentEncoding.getConstructorSize()
264                                 + componentEncoding.getValueSize(null) * componentCount;
265                 }
266                 else
267                 {
268                     size += encoder.getValueSize(o);
269                 }
270             }
271         }
272 
273         return size;
274     }
275 
276     override
277     public ArrayEncoding getCanonicalEncoding()
278     {
279         return _arrayEncoding;
280     }
281 
282     override
283     public Collection!(ArrayEncoding) getAllEncodings()
284     {
285         return Arrays.asList(_shortArrayEncoding, _arrayEncoding);
286     }
287 
288     override
289     public void write(Object[] val)
290     {
291         ArrayEncoding encoding = getEncoding(val);
292         encoding.writeConstructor();
293         encoding.writeValue(val);
294     }
295 
296     public void write(bool[] a)
297     {
298         ArrayEncoding encoding = getEncoding(a);
299         encoding.writeConstructor();
300         encoding.writeValue(a);
301     }
302 
303     private ArrayEncoding getEncoding(bool[] a)
304     {
305         return a.length < 254 || a.length <= 255 && allSameValue(a) ? _shortArrayEncoding : _arrayEncoding;
306     }
307 
308     private bool allSameValue(bool[] a)
309     {
310         bool val = a[0];
311         for(int i = 1; i < a.length; i++)
312         {
313             if(val != a[i])
314             {
315                 return false;
316             }
317         }
318         return true;
319     }
320 
321     public void write(byte[] a)
322     {
323         ArrayEncoding encoding = getEncoding(a);
324         encoding.writeConstructor();
325         encoding.writeValue(a);
326     }
327 
328     private ArrayEncoding getEncoding(byte[] a)
329     {
330         return a.length < 254 ? _shortArrayEncoding : _arrayEncoding;
331     }
332 
333     public void write(short[] a)
334     {
335         ArrayEncoding encoding = getEncoding(a);
336         encoding.writeConstructor();
337         encoding.writeValue(a);
338     }
339 
340     private ArrayEncoding getEncoding(short[] a)
341     {
342         return a.length < 127 ? _shortArrayEncoding : _arrayEncoding;
343     }
344 
345     public void write(int[] a)
346     {
347         ArrayEncoding encoding = getEncoding(a);
348         encoding.writeConstructor();
349         encoding.writeValue(a);
350     }
351 
352     private ArrayEncoding getEncoding(int[] a)
353     {
354         return a.length < 63 || (a.length < 254 && allSmallInts(a)) ? _shortArrayEncoding : _arrayEncoding;
355     }
356 
357     private bool allSmallInts(int[] a)
358     {
359         for(int i = 0; i < a.length; i++)
360         {
361             if(a[i] < -128 || a[i] > 127)
362             {
363                 return false;
364             }
365         }
366         return true;
367     }
368 
369     public void write(long[] a)
370     {
371         ArrayEncoding encoding = getEncoding(a);
372         encoding.writeConstructor();
373         encoding.writeValue(a);
374     }
375 
376     private ArrayEncoding getEncoding(long[] a)
377     {
378         return a.length < 31 || (a.length < 254 && allSmallLongs(a)) ? _shortArrayEncoding : _arrayEncoding;
379     }
380 
381     private bool allSmallLongs(long[] a)
382     {
383         for(int i = 0; i < a.length; i++)
384         {
385             if(a[i] < -128L || a[i] > 127L)
386             {
387                 return false;
388             }
389         }
390         return true;
391     }
392 
393     public void write(float[] a)
394     {
395         ArrayEncoding encoding = getEncoding(a);
396         encoding.writeConstructor();
397         encoding.writeValue(a);
398     }
399 
400     private ArrayEncoding getEncoding(float[] a)
401     {
402         return a.length < 63 ? _shortArrayEncoding : _arrayEncoding;
403     }
404 
405     public void write(double[] a)
406     {
407         ArrayEncoding encoding = getEncoding(a);
408         encoding.writeConstructor();
409         encoding.writeValue(a);
410     }
411 
412     private ArrayEncoding getEncoding(double[] a)
413     {
414         return a.length < 31 ? _shortArrayEncoding : _arrayEncoding;
415     }
416 
417     public void write(char[] a)
418     {
419         ArrayEncoding encoding = getEncoding(a);
420         encoding.writeConstructor();
421         encoding.writeValue(a);
422     }
423 
424     private ArrayEncoding getEncoding(char[] a)
425     {
426         return a.length < 63 ? _shortArrayEncoding : _arrayEncoding;
427     }
428 
429     private class AllArrayEncoding
430             : LargeFloatingSizePrimitiveTypeEncoding!(Object[])
431             implements ArrayEncoding
432     {
433         private Object[] _val;
434         private TypeEncoding _underlyingEncoder;
435         private int _size;
436 
437         AllArrayEncoding(EncoderImpl encoder, DecoderImpl decoder)
438         {
439             super(encoder, decoder);
440         }
441 
442         override
443         protected void writeSize(Object[] val)
444         {
445             int encodedValueSize = getEncodedValueSize(val);
446             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
447             getEncoder().writeRaw(encodedValueSize);
448         }
449 
450         override
451         public void writeValue(bool[] a)
452         {
453             BooleanType.BooleanEncoding underlyingEncoder = getUnderlyingEncoding(a);
454             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
455                                    a.length * underlyingEncoder.getValueSize(null);
456             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
457             getEncoder().writeRaw(encodedValueSize);
458             getEncoder().writeRaw(a.length);
459             underlyingEncoder.writeConstructor();
460             for(bool b : a)
461             {
462                 underlyingEncoder.writeValue(b);
463             }
464         }
465 
466         override
467         public void writeValue(byte[] a)
468         {
469             ByteType.ByteEncoding underlyingEncoder = getUnderlyingEncoding(a);
470             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
471                                    a.length * underlyingEncoder.getValueSize(null);
472             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
473             getEncoder().writeRaw(encodedValueSize);
474             getEncoder().writeRaw(a.length);
475             underlyingEncoder.writeConstructor();
476             for(byte b : a)
477             {
478                 underlyingEncoder.writeValue(b);
479             }
480         }
481 
482         override
483         public void writeValue(short[] a)
484         {
485             ShortType.ShortEncoding underlyingEncoder = getUnderlyingEncoding(a);
486             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
487                                    a.length * underlyingEncoder.getValueSize(null);
488             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
489             getEncoder().writeRaw(encodedValueSize);
490             getEncoder().writeRaw(a.length);
491             underlyingEncoder.writeConstructor();
492             for(short b : a)
493             {
494                 underlyingEncoder.writeValue(b);
495             }
496         }
497 
498         override
499         public void writeValue(int[] a)
500         {
501             IntegerType.IntegerEncoding underlyingEncoder = getUnderlyingEncoding(a);
502             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
503                                    a.length * underlyingEncoder.getValueSize(null);
504             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
505             getEncoder().writeRaw(encodedValueSize);
506             getEncoder().writeRaw(a.length);
507             underlyingEncoder.writeConstructor();
508             for(int b : a)
509             {
510                 underlyingEncoder.writeValue(b);
511             }
512         }
513 
514         override
515         public void writeValue(long[] a)
516         {
517             LongType.LongEncoding underlyingEncoder = getUnderlyingEncoding(a);
518             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
519                                    a.length * underlyingEncoder.getValueSize(null);
520             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
521             getEncoder().writeRaw(encodedValueSize);
522             getEncoder().writeRaw(a.length);
523             underlyingEncoder.writeConstructor();
524             for(long b : a)
525             {
526                 underlyingEncoder.writeValue(b);
527             }
528         }
529 
530         override
531         public void writeValue(float[] a)
532         {
533             FloatType.FloatEncoding underlyingEncoder = getUnderlyingEncoding(a);
534             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
535                                    a.length * underlyingEncoder.getValueSize(null);
536             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
537             getEncoder().writeRaw(encodedValueSize);
538             getEncoder().writeRaw(a.length);
539             underlyingEncoder.writeConstructor();
540             for(float b : a)
541             {
542                 underlyingEncoder.writeValue(b);
543             }
544         }
545 
546         override
547         public void writeValue(double[] a)
548         {
549             DoubleType.DoubleEncoding underlyingEncoder = getUnderlyingEncoding(a);
550             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
551                                    a.length * underlyingEncoder.getValueSize(null);
552             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
553             getEncoder().writeRaw(encodedValueSize);
554             getEncoder().writeRaw(a.length);
555             underlyingEncoder.writeConstructor();
556             for(double b : a)
557             {
558                 underlyingEncoder.writeValue(b);
559             }
560         }
561 
562         override
563         public void writeValue(char[] a)
564         {
565             CharacterType.CharacterEncoding underlyingEncoder = getUnderlyingEncoding(a);
566             int encodedValueSize = 4 + underlyingEncoder.getConstructorSize() +
567                                    a.length * underlyingEncoder.getValueSize(null);
568             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
569             getEncoder().writeRaw(encodedValueSize);
570             getEncoder().writeRaw(a.length);
571             underlyingEncoder.writeConstructor();
572             for(char b : a)
573             {
574                 underlyingEncoder.writeValue(b);
575             }
576         }
577 
578         override
579         public void setValue(Object[] val, TypeEncoding encoder, int size)
580         {
581             _val = val;
582             _underlyingEncoder = encoder;
583             _size = size;
584         }
585 
586         override
587         protected void writeEncodedValue(Object[] val)
588         {
589             TypeEncoding underlyingEncoder;
590 
591             if(_val != val)
592             {
593                 _val = val;
594                 _underlyingEncoder = underlyingEncoder = calculateEncoder(val, getEncoder());
595                 _size =  calculateSize(val, underlyingEncoder);
596             }
597             else
598             {
599                 underlyingEncoder = _underlyingEncoder;
600             }
601             getEncoder().writeRaw(val.length);
602             underlyingEncoder.writeConstructor();
603             for(Object o : val)
604             {
605                 underlyingEncoder.writeValue(o);
606             }
607         }
608 
609         override
610         protected int getEncodedValueSize(Object[] val)
611         {
612             if(_val != val)
613             {
614                 _val = val;
615                 _underlyingEncoder = calculateEncoder(val, getEncoder());
616                 _size = calculateSize(val, _underlyingEncoder);
617             }
618             return 4 + _size;
619         }
620 
621         override
622         public byte getEncodingCode()
623         {
624             return EncodingCodes.ARRAY32;
625         }
626 
627         override
628         public ArrayType getType()
629         {
630             return ArrayType.this;
631         }
632 
633         override
634         public bool encodesSuperset(TypeEncoding!(Object[]) encoding)
635         {
636             return getType() == encoding.getType();
637         }
638 
639         override
640         public Object[] readValue()
641         {
642             DecoderImpl decoder = getDecoder();
643             int size = decoder.readRawInt();
644             int count = decoder.readRawInt();
645             return decodeArray(decoder, count);
646         }
647 
648         override
649         public Object readValueArray()
650         {
651             DecoderImpl decoder = getDecoder();
652             int size = decoder.readRawInt();
653             int count = decoder.readRawInt();
654             return decodeArrayAsObject(decoder, count);
655         }
656 
657         override
658         public void skipValue()
659         {
660             DecoderImpl decoder = getDecoder();
661             ReadableBuffer buffer = decoder.getBuffer();
662             int size = decoder.readRawInt();
663             buffer.position(buffer.position() + size);
664         }
665     }
666 
667     private class ShortArrayEncoding
668             : SmallFloatingSizePrimitiveTypeEncoding!(Object[])
669             implements ArrayEncoding
670     {
671         private Object[] _val;
672         private TypeEncoding _underlyingEncoder;
673         private int _size;
674 
675         ShortArrayEncoding(EncoderImpl encoder, DecoderImpl decoder)
676         {
677             super(encoder, decoder);
678         }
679 
680         override
681         protected void writeSize(Object[] val)
682         {
683             int encodedValueSize = getEncodedValueSize(val);
684             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
685             getEncoder().writeRaw((byte) encodedValueSize);
686         }
687 
688         override
689         public void writeValue(bool[] a)
690         {
691             BooleanType.BooleanEncoding underlyingEncoder = getUnderlyingEncoding(a);
692             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
693                                     a.length * underlyingEncoder.getValueSize(null);
694             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
695             getEncoder().writeRaw((byte)encodedValueSize);
696             getEncoder().writeRaw((byte)a.length);
697             underlyingEncoder.writeConstructor();
698             for(bool b : a)
699             {
700                 underlyingEncoder.writeValue(b);
701             }
702         }
703 
704         override
705         public void writeValue(byte[] a)
706         {
707             ByteType.ByteEncoding underlyingEncoder = getUnderlyingEncoding(a);
708             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
709                                     a.length * underlyingEncoder.getValueSize(null);
710             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
711             getEncoder().writeRaw((byte)encodedValueSize);
712             getEncoder().writeRaw((byte)a.length);
713             underlyingEncoder.writeConstructor();
714             for(byte b : a)
715             {
716                 underlyingEncoder.writeValue(b);
717             }
718         }
719 
720         override
721         public void writeValue(short[] a)
722         {
723             ShortType.ShortEncoding underlyingEncoder = getUnderlyingEncoding(a);
724             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
725                                     a.length * underlyingEncoder.getValueSize(null);
726             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
727             getEncoder().writeRaw((byte)encodedValueSize);
728             getEncoder().writeRaw((byte)a.length);
729             underlyingEncoder.writeConstructor();
730             for(short b : a)
731             {
732                 underlyingEncoder.writeValue(b);
733             }
734         }
735 
736         override
737         public void writeValue(int[] a)
738         {
739             IntegerType.IntegerEncoding underlyingEncoder = getUnderlyingEncoding(a);
740             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
741                                     a.length * underlyingEncoder.getValueSize(null);
742             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
743             getEncoder().writeRaw((byte)encodedValueSize);
744             getEncoder().writeRaw((byte)a.length);
745             underlyingEncoder.writeConstructor();
746             for(int b : a)
747             {
748                 underlyingEncoder.writeValue(b);
749             }
750         }
751 
752         override
753         public void writeValue(long[] a)
754         {
755             LongType.LongEncoding underlyingEncoder = getUnderlyingEncoding(a);
756             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
757                                     a.length * underlyingEncoder.getValueSize(null);
758             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
759             getEncoder().writeRaw((byte)encodedValueSize);
760             getEncoder().writeRaw((byte)a.length);
761             underlyingEncoder.writeConstructor();
762             for(long b : a)
763             {
764                 underlyingEncoder.writeValue(b);
765             }
766         }
767 
768         override
769         public void writeValue(float[] a)
770         {
771             FloatType.FloatEncoding underlyingEncoder = getUnderlyingEncoding(a);
772             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
773                                     a.length * underlyingEncoder.getValueSize(null);
774             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
775             getEncoder().writeRaw((byte)encodedValueSize);
776             getEncoder().writeRaw((byte)a.length);
777             underlyingEncoder.writeConstructor();
778             for(float b : a)
779             {
780                 underlyingEncoder.writeValue(b);
781             }
782         }
783 
784         override
785         public void writeValue(double[] a)
786         {
787             DoubleType.DoubleEncoding underlyingEncoder = getUnderlyingEncoding(a);
788             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
789                                     a.length * underlyingEncoder.getValueSize(null);
790             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
791             getEncoder().writeRaw((byte)encodedValueSize);
792             getEncoder().writeRaw((byte)a.length);
793             underlyingEncoder.writeConstructor();
794             for(double b : a)
795             {
796                 underlyingEncoder.writeValue(b);
797             }
798         }
799 
800         override
801         public void writeValue(char[] a)
802         {
803             CharacterType.CharacterEncoding underlyingEncoder = getUnderlyingEncoding(a);
804             int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
805                                     a.length * underlyingEncoder.getValueSize(null);
806             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
807             getEncoder().writeRaw((byte)encodedValueSize);
808             getEncoder().writeRaw((byte)a.length);
809             underlyingEncoder.writeConstructor();
810             for(char b : a)
811             {
812                 underlyingEncoder.writeValue(b);
813             }
814         }
815 
816         override
817         public void setValue(Object[] val, TypeEncoding encoder, int size)
818         {
819             _val = val;
820             _underlyingEncoder = encoder;
821             _size = size;
822         }
823 
824         override
825         protected void writeEncodedValue(Object[] val)
826         {
827             TypeEncoding underlyingEncoder;
828 
829             if(_val != val)
830             {
831                 _val = val;
832                 _underlyingEncoder = underlyingEncoder = calculateEncoder(val, getEncoder());
833                 _size =  calculateSize(val, underlyingEncoder);
834             }
835             else
836             {
837                 underlyingEncoder = _underlyingEncoder;
838             }
839             getEncoder().writeRaw((byte)val.length);
840             underlyingEncoder.writeConstructor();
841             for(Object o : val)
842             {
843                 if(o.getClass().isArray() && o.getClass().getComponentType().isPrimitive())
844                 {
845                     ArrayEncoding arrayEncoding = (ArrayEncoding) underlyingEncoder;
846                     ArrayType arrayType = (ArrayType) arrayEncoding.getType();
847 
848                     Class componentType = o.getClass().getComponentType();
849 
850                     if(componentType == Boolean.TYPE)
851                     {
852                         bool[] componentArray = (bool[]) o;
853                         arrayEncoding.writeValue(componentArray);
854                     }
855                     else if(componentType == Byte.TYPE)
856                     {
857                         byte[] componentArray = (byte[]) o;
858                         arrayEncoding.writeValue(componentArray);
859                     }
860                     else if(componentType == Short.TYPE)
861                     {
862                         short[] componentArray = (short[]) o;
863                         arrayEncoding.writeValue(componentArray);
864                     }
865                     else if(componentType == Integer.TYPE)
866                     {
867                         int[] componentArray = (int[]) o;
868                         arrayEncoding.writeValue(componentArray);
869                     }
870                     else if(componentType == Long.TYPE)
871                     {
872                         long[] componentArray = (long[]) o;
873                         arrayEncoding.writeValue(componentArray);
874                     }
875                     else if(componentType == Float.TYPE)
876                     {
877                         float[] componentArray = (float[]) o;
878                         arrayEncoding.writeValue(componentArray);
879                     }
880                     else if(componentType == Double.TYPE)
881                     {
882                         double[] componentArray = (double[]) o;
883                         arrayEncoding.writeValue(componentArray);
884                     }
885                     else if(componentType == Character.TYPE)
886                     {
887                         char[] componentArray = (char[]) o;
888                         arrayEncoding.writeValue(componentArray);
889                     }
890                     else
891                     {
892                         throw new IllegalArgumentException("Cannot encode arrays of type " ~ componentType.getName());
893                     }
894                 }
895                 else
896                 {
897                     underlyingEncoder.writeValue(o);
898                 }
899             }
900         }
901 
902         override
903         protected int getEncodedValueSize(Object[] val)
904         {
905             if(_val != val)
906             {
907                 _val = val;
908                 _underlyingEncoder = calculateEncoder(val, getEncoder());
909                 _size = calculateSize(val, _underlyingEncoder);
910             }
911             return 1 + _size;
912         }
913 
914         override
915         public byte getEncodingCode()
916         {
917             return EncodingCodes.ARRAY8;
918         }
919 
920         override
921         public ArrayType getType()
922         {
923             return ArrayType.this;
924         }
925 
926         override
927         public bool encodesSuperset(TypeEncoding!(Object[]) encoding)
928         {
929             return getType() == encoding.getType();
930         }
931 
932         override
933         public Object[] readValue()
934         {
935             DecoderImpl decoder = getDecoder();
936             int size = ((int)decoder.readRawByte()) & 0xFF;
937             int count = ((int)decoder.readRawByte()) & 0xFF;
938             return decodeArray(decoder, count);
939         }
940 
941         override
942         public Object readValueArray()
943         {
944             DecoderImpl decoder = getDecoder();
945             int size = ((int)decoder.readRawByte()) & 0xFF;
946             int count = ((int)decoder.readRawByte()) & 0xFF;
947             return decodeArrayAsObject(decoder, count);
948         }
949 
950         override
951         public void skipValue()
952         {
953             DecoderImpl decoder = getDecoder();
954             ReadableBuffer buffer = decoder.getBuffer();
955             int size = ((int)decoder.readRawByte()) & 0xFF;
956             buffer.position(buffer.position() + size);
957         }
958     }
959 
960     private BooleanType.BooleanEncoding getUnderlyingEncoding(bool[] a)
961     {
962         if(a.length == 0)
963         {
964             return _boolType.getCanonicalEncoding();
965         }
966         else
967         {
968             bool val = a[0];
969             for(int i = 1; i < a.length; i++)
970             {
971                 if(val != a[i])
972                 {
973                     return _boolType.getCanonicalEncoding();
974                 }
975             }
976             return _boolType.getEncoding(val);
977         }
978     }
979 
980     private ByteType.ByteEncoding getUnderlyingEncoding(byte[] a)
981     {
982         return _byteType.getCanonicalEncoding();
983     }
984 
985     private ShortType.ShortEncoding getUnderlyingEncoding(short[] a)
986     {
987         return _shortType.getCanonicalEncoding();
988     }
989 
990     private IntegerType.IntegerEncoding getUnderlyingEncoding(int[] a)
991     {
992         if(a.length == 0 || !allSmallInts(a))
993         {
994             return _integerType.getCanonicalEncoding();
995         }
996         else
997         {
998             return _integerType.getEncoding(a[0]);
999         }
1000     }
1001 
1002     private LongType.LongEncoding getUnderlyingEncoding(long[] a)
1003     {
1004         if(a.length == 0 || !allSmallLongs(a))
1005         {
1006             return _longType.getCanonicalEncoding();
1007         }
1008         else
1009         {
1010             return _longType.getEncoding(a[0]);
1011         }
1012     }
1013 
1014     private FloatType.FloatEncoding getUnderlyingEncoding(float[] a)
1015     {
1016         return _floatType.getCanonicalEncoding();
1017     }
1018 
1019     private DoubleType.DoubleEncoding getUnderlyingEncoding(double[] a)
1020     {
1021         return _doubleType.getCanonicalEncoding();
1022     }
1023 
1024     private CharacterType.CharacterEncoding getUnderlyingEncoding(char[] a)
1025     {
1026         return _characterType.getCanonicalEncoding();
1027     }
1028 
1029     private static Object[] decodeArray(DecoderImpl decoder, int count)
1030     {
1031         TypeConstructor constructor = decoder.readConstructor(true);
1032         return decodeNonPrimitive(decoder, constructor, count);
1033     }
1034 
1035     private static Object[] decodeNonPrimitive(DecoderImpl decoder,
1036                                                TypeConstructor constructor,
1037                                                int count)
1038     {
1039         if (count > decoder.getByteBufferRemaining()) {
1040             throw new IllegalArgumentException("Array element count "+count+" is specified to be greater than the amount of data available ("+
1041                                                decoder.getByteBufferRemaining()+")");
1042         }
1043 
1044         if(constructor instanceof ArrayEncoding)
1045         {
1046             ArrayEncoding arrayEncoding = (ArrayEncoding) constructor;
1047 
1048             Object[] array = new Object[count];
1049             for(int i = 0; i < count; i++)
1050             {
1051                 array[i] = arrayEncoding.readValueArray();
1052             }
1053 
1054             return array;
1055         }
1056         else
1057         {
1058             Object[] array = (Object[]) Array.newInstance(constructor.getTypeClass(), count);
1059 
1060             for(int i = 0; i < count; i++)
1061             {
1062                 array[i] = constructor.readValue();
1063             }
1064 
1065             return array;
1066         }
1067     }
1068 
1069     private static Object decodeArrayAsObject(DecoderImpl decoder, int count)
1070     {
1071         TypeConstructor constructor = decoder.readConstructor(true);
1072         if(constructor.encodesJavaPrimitive())
1073         {
1074             if (count > decoder.getByteBufferRemaining()) {
1075                 throw new IllegalArgumentException("Array element count "+count+" is specified to be greater than the amount of data available ("+
1076                                                    decoder.getByteBufferRemaining()+")");
1077             }
1078 
1079             if(constructor instanceof BooleanType.BooleanEncoding)
1080             {
1081                 return decodeBooleanArray((BooleanType.BooleanEncoding) constructor, count);
1082             }
1083             else if(constructor instanceof ByteType.ByteEncoding)
1084             {
1085                 return decodeByteArray((ByteType.ByteEncoding)constructor, count);
1086             }
1087             else if(constructor instanceof ShortType.ShortEncoding)
1088             {
1089                 return decodeShortArray((ShortType.ShortEncoding)constructor, count);
1090             }
1091             else if(constructor instanceof IntegerType.IntegerEncoding)
1092             {
1093                 return decodeIntArray((IntegerType.IntegerEncoding)constructor, count);
1094             }
1095             else if(constructor instanceof LongType.LongEncoding)
1096             {
1097                 return decodeLongArray((LongType.LongEncoding) constructor, count);
1098             }
1099             else if(constructor instanceof FloatType.FloatEncoding)
1100             {
1101                 return decodeFloatArray((FloatType.FloatEncoding) constructor, count);
1102             }
1103             else if(constructor instanceof DoubleType.DoubleEncoding)
1104             {
1105                 return decodeDoubleArray((DoubleType.DoubleEncoding)constructor, count);
1106             }
1107             else if(constructor instanceof CharacterType.CharacterEncoding)
1108             {
1109                 return decodeCharArray((CharacterType.CharacterEncoding)constructor, count);
1110             }
1111             else
1112             {
1113                 throw new ClassCastException("Unexpected class " ~ constructor.getClass().getName());
1114             }
1115         }
1116         else
1117         {
1118             return decodeNonPrimitive(decoder, constructor, count);
1119         }
1120     }
1121 
1122     private static bool[] decodeBooleanArray(BooleanType.BooleanEncoding constructor, int count)
1123     {
1124         bool[] array = new bool[count];
1125 
1126         for(int i = 0; i < count; i++)
1127         {
1128             array[i] = constructor.readPrimitiveValue();
1129         }
1130 
1131         return array;
1132     }
1133 
1134     private static byte[] decodeByteArray(ByteType.ByteEncoding constructor , int count)
1135     {
1136         byte[] array = new byte[count];
1137 
1138         for(int i = 0; i < count; i++)
1139         {
1140             array[i] = constructor.readPrimitiveValue();
1141         }
1142 
1143         return array;
1144     }
1145 
1146     private static short[] decodeShortArray(ShortType.ShortEncoding constructor, int count)
1147     {
1148         short[] array = new short[count];
1149 
1150         for(int i = 0; i < count; i++)
1151         {
1152             array[i] = constructor.readPrimitiveValue();
1153         }
1154 
1155         return array;
1156     }
1157 
1158     private static int[] decodeIntArray(IntegerType.IntegerEncoding constructor, int count)
1159     {
1160         int[] array = new int[count];
1161 
1162         for(int i = 0; i < count; i++)
1163         {
1164             array[i] = constructor.readPrimitiveValue();
1165         }
1166 
1167         return array;
1168     }
1169 
1170     private static long[] decodeLongArray(LongType.LongEncoding constructor, int count)
1171     {
1172         long[] array = new long[count];
1173 
1174         for(int i = 0; i < count; i++)
1175         {
1176             array[i] = constructor.readPrimitiveValue();
1177         }
1178 
1179         return array;
1180     }
1181 
1182     private static float[] decodeFloatArray(FloatType.FloatEncoding constructor, int count)
1183     {
1184         float[] array = new float[count];
1185 
1186         for(int i = 0; i < count; i++)
1187         {
1188             array[i] = constructor.readPrimitiveValue();
1189         }
1190 
1191         return array;
1192     }
1193 
1194     private static double[] decodeDoubleArray(DoubleType.DoubleEncoding constructor, int count)
1195     {
1196         double[] array = new double[count];
1197 
1198         for(int i = 0; i < count; i++)
1199         {
1200             array[i] = constructor.readPrimitiveValue();
1201         }
1202 
1203         return array;
1204     }
1205 
1206     private static char[] decodeCharArray(CharacterType.CharacterEncoding constructor, int count)
1207     {
1208         char[] array = new char[count];
1209 
1210         for(int i = 0; i < count; i++)
1211         {
1212             array[i] = constructor.readPrimitiveValue();
1213         }
1214 
1215         return array;
1216     }
1217 }
1218 
1219 */