1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.mvstore.type; |
7 | |
8 | import java.io.ByteArrayInputStream; |
9 | import java.io.ByteArrayOutputStream; |
10 | import java.io.ObjectInputStream; |
11 | import java.io.ObjectOutputStream; |
12 | import java.lang.reflect.Array; |
13 | import java.math.BigDecimal; |
14 | import java.math.BigInteger; |
15 | import java.nio.ByteBuffer; |
16 | import java.util.Arrays; |
17 | import java.util.Date; |
18 | import java.util.HashMap; |
19 | import java.util.UUID; |
20 | import org.h2.mvstore.DataUtils; |
21 | import org.h2.mvstore.WriteBuffer; |
22 | import org.h2.util.New; |
23 | |
24 | /** |
25 | * A data type implementation for the most common data types, including |
26 | * serializable objects. |
27 | */ |
28 | public class ObjectDataType implements DataType { |
29 | |
30 | /** |
31 | * The type constants are also used as tag values. |
32 | */ |
33 | static final int TYPE_NULL = 0; |
34 | static final int TYPE_BOOLEAN = 1; |
35 | static final int TYPE_BYTE = 2; |
36 | static final int TYPE_SHORT = 3; |
37 | static final int TYPE_INT = 4; |
38 | static final int TYPE_LONG = 5; |
39 | static final int TYPE_BIG_INTEGER = 6; |
40 | static final int TYPE_FLOAT = 7; |
41 | static final int TYPE_DOUBLE = 8; |
42 | static final int TYPE_BIG_DECIMAL = 9; |
43 | static final int TYPE_CHAR = 10; |
44 | static final int TYPE_STRING = 11; |
45 | static final int TYPE_UUID = 12; |
46 | static final int TYPE_DATE = 13; |
47 | static final int TYPE_ARRAY = 14; |
48 | static final int TYPE_SERIALIZED_OBJECT = 19; |
49 | |
50 | /** |
51 | * For very common values (e.g. 0 and 1) we save space by encoding the value |
52 | * in the tag. e.g. TAG_BOOLEAN_TRUE and TAG_FLOAT_0. |
53 | */ |
54 | static final int TAG_BOOLEAN_TRUE = 32; |
55 | static final int TAG_INTEGER_NEGATIVE = 33; |
56 | static final int TAG_INTEGER_FIXED = 34; |
57 | static final int TAG_LONG_NEGATIVE = 35; |
58 | static final int TAG_LONG_FIXED = 36; |
59 | static final int TAG_BIG_INTEGER_0 = 37; |
60 | static final int TAG_BIG_INTEGER_1 = 38; |
61 | static final int TAG_BIG_INTEGER_SMALL = 39; |
62 | static final int TAG_FLOAT_0 = 40; |
63 | static final int TAG_FLOAT_1 = 41; |
64 | static final int TAG_FLOAT_FIXED = 42; |
65 | static final int TAG_DOUBLE_0 = 43; |
66 | static final int TAG_DOUBLE_1 = 44; |
67 | static final int TAG_DOUBLE_FIXED = 45; |
68 | static final int TAG_BIG_DECIMAL_0 = 46; |
69 | static final int TAG_BIG_DECIMAL_1 = 47; |
70 | static final int TAG_BIG_DECIMAL_SMALL = 48; |
71 | static final int TAG_BIG_DECIMAL_SMALL_SCALED = 49; |
72 | |
73 | /** |
74 | * For small-values/small-arrays, we encode the value/array-length in the |
75 | * tag. |
76 | */ |
77 | static final int TAG_INTEGER_0_15 = 64; |
78 | static final int TAG_LONG_0_7 = 80; |
79 | static final int TAG_STRING_0_15 = 88; |
80 | static final int TAG_BYTE_ARRAY_0_15 = 104; |
81 | |
82 | /** |
83 | * Constants for floating point synchronization. |
84 | */ |
85 | static final int FLOAT_ZERO_BITS = Float.floatToIntBits(0.0f); |
86 | static final int FLOAT_ONE_BITS = Float.floatToIntBits(1.0f); |
87 | static final long DOUBLE_ZERO_BITS = Double.doubleToLongBits(0.0d); |
88 | static final long DOUBLE_ONE_BITS = Double.doubleToLongBits(1.0d); |
89 | |
90 | static final Class<?>[] COMMON_CLASSES = { boolean.class, byte.class, |
91 | short.class, char.class, int.class, long.class, float.class, |
92 | double.class, Object.class, Boolean.class, Byte.class, Short.class, |
93 | Character.class, Integer.class, Long.class, BigInteger.class, |
94 | Float.class, Double.class, BigDecimal.class, String.class, |
95 | UUID.class, Date.class }; |
96 | |
97 | private static final HashMap<Class<?>, Integer> COMMON_CLASSES_MAP = New |
98 | .hashMap(); |
99 | |
100 | private AutoDetectDataType last = new StringType(this); |
101 | |
102 | @Override |
103 | public int compare(Object a, Object b) { |
104 | return last.compare(a, b); |
105 | } |
106 | |
107 | @Override |
108 | public int getMemory(Object obj) { |
109 | return last.getMemory(obj); |
110 | } |
111 | |
112 | @Override |
113 | public void read(ByteBuffer buff, Object[] obj, int len, boolean key) { |
114 | for (int i = 0; i < len; i++) { |
115 | obj[i] = read(buff); |
116 | } |
117 | } |
118 | |
119 | @Override |
120 | public void write(WriteBuffer buff, Object[] obj, int len, boolean key) { |
121 | for (int i = 0; i < len; i++) { |
122 | write(buff, obj[i]); |
123 | } |
124 | } |
125 | |
126 | @Override |
127 | public void write(WriteBuffer buff, Object obj) { |
128 | last.write(buff, obj); |
129 | } |
130 | |
131 | private AutoDetectDataType newType(int typeId) { |
132 | switch (typeId) { |
133 | case TYPE_NULL: |
134 | return new NullType(this); |
135 | case TYPE_BOOLEAN: |
136 | return new BooleanType(this); |
137 | case TYPE_BYTE: |
138 | return new ByteType(this); |
139 | case TYPE_SHORT: |
140 | return new ShortType(this); |
141 | case TYPE_CHAR: |
142 | return new CharacterType(this); |
143 | case TYPE_INT: |
144 | return new IntegerType(this); |
145 | case TYPE_LONG: |
146 | return new LongType(this); |
147 | case TYPE_FLOAT: |
148 | return new FloatType(this); |
149 | case TYPE_DOUBLE: |
150 | return new DoubleType(this); |
151 | case TYPE_BIG_INTEGER: |
152 | return new BigIntegerType(this); |
153 | case TYPE_BIG_DECIMAL: |
154 | return new BigDecimalType(this); |
155 | case TYPE_STRING: |
156 | return new StringType(this); |
157 | case TYPE_UUID: |
158 | return new UUIDType(this); |
159 | case TYPE_DATE: |
160 | return new DateType(this); |
161 | case TYPE_ARRAY: |
162 | return new ObjectArrayType(this); |
163 | case TYPE_SERIALIZED_OBJECT: |
164 | return new SerializedObjectType(this); |
165 | } |
166 | throw DataUtils.newIllegalStateException(DataUtils.ERROR_INTERNAL, |
167 | "Unsupported type {0}", typeId); |
168 | } |
169 | |
170 | @Override |
171 | public Object read(ByteBuffer buff) { |
172 | int tag = buff.get(); |
173 | int typeId; |
174 | if (tag <= TYPE_SERIALIZED_OBJECT) { |
175 | typeId = tag; |
176 | } else { |
177 | switch (tag) { |
178 | case TAG_BOOLEAN_TRUE: |
179 | typeId = TYPE_BOOLEAN; |
180 | break; |
181 | case TAG_INTEGER_NEGATIVE: |
182 | case TAG_INTEGER_FIXED: |
183 | typeId = TYPE_INT; |
184 | break; |
185 | case TAG_LONG_NEGATIVE: |
186 | case TAG_LONG_FIXED: |
187 | typeId = TYPE_LONG; |
188 | break; |
189 | case TAG_BIG_INTEGER_0: |
190 | case TAG_BIG_INTEGER_1: |
191 | case TAG_BIG_INTEGER_SMALL: |
192 | typeId = TYPE_BIG_INTEGER; |
193 | break; |
194 | case TAG_FLOAT_0: |
195 | case TAG_FLOAT_1: |
196 | case TAG_FLOAT_FIXED: |
197 | typeId = TYPE_FLOAT; |
198 | break; |
199 | case TAG_DOUBLE_0: |
200 | case TAG_DOUBLE_1: |
201 | case TAG_DOUBLE_FIXED: |
202 | typeId = TYPE_DOUBLE; |
203 | break; |
204 | case TAG_BIG_DECIMAL_0: |
205 | case TAG_BIG_DECIMAL_1: |
206 | case TAG_BIG_DECIMAL_SMALL: |
207 | case TAG_BIG_DECIMAL_SMALL_SCALED: |
208 | typeId = TYPE_BIG_DECIMAL; |
209 | break; |
210 | default: |
211 | if (tag >= TAG_INTEGER_0_15 && tag <= TAG_INTEGER_0_15 + 15) { |
212 | typeId = TYPE_INT; |
213 | } else if (tag >= TAG_STRING_0_15 |
214 | && tag <= TAG_STRING_0_15 + 15) { |
215 | typeId = TYPE_STRING; |
216 | } else if (tag >= TAG_LONG_0_7 && tag <= TAG_LONG_0_7 + 7) { |
217 | typeId = TYPE_LONG; |
218 | } else if (tag >= TAG_BYTE_ARRAY_0_15 |
219 | && tag <= TAG_BYTE_ARRAY_0_15 + 15) { |
220 | typeId = TYPE_ARRAY; |
221 | } else { |
222 | throw DataUtils.newIllegalStateException( |
223 | DataUtils.ERROR_FILE_CORRUPT, "Unknown tag {0}", |
224 | tag); |
225 | } |
226 | } |
227 | } |
228 | AutoDetectDataType t = last; |
229 | if (typeId != t.typeId) { |
230 | last = t = newType(typeId); |
231 | } |
232 | return t.read(buff, tag); |
233 | } |
234 | |
235 | private static int getTypeId(Object obj) { |
236 | if (obj instanceof Integer) { |
237 | return TYPE_INT; |
238 | } else if (obj instanceof String) { |
239 | return TYPE_STRING; |
240 | } else if (obj instanceof Long) { |
241 | return TYPE_LONG; |
242 | } else if (obj instanceof Double) { |
243 | return TYPE_DOUBLE; |
244 | } else if (obj instanceof Float) { |
245 | return TYPE_FLOAT; |
246 | } else if (obj instanceof Boolean) { |
247 | return TYPE_BOOLEAN; |
248 | } else if (obj instanceof UUID) { |
249 | return TYPE_UUID; |
250 | } else if (obj instanceof Byte) { |
251 | return TYPE_BYTE; |
252 | } else if (obj instanceof Short) { |
253 | return TYPE_SHORT; |
254 | } else if (obj instanceof Character) { |
255 | return TYPE_CHAR; |
256 | } else if (obj == null) { |
257 | return TYPE_NULL; |
258 | } else if (isDate(obj)) { |
259 | return TYPE_DATE; |
260 | } else if (isBigInteger(obj)) { |
261 | return TYPE_BIG_INTEGER; |
262 | } else if (isBigDecimal(obj)) { |
263 | return TYPE_BIG_DECIMAL; |
264 | } else if (obj.getClass().isArray()) { |
265 | return TYPE_ARRAY; |
266 | } |
267 | return TYPE_SERIALIZED_OBJECT; |
268 | } |
269 | |
270 | /** |
271 | * Switch the last remembered type to match the type of the given object. |
272 | * |
273 | * @param obj the object |
274 | * @return the auto-detected type used |
275 | */ |
276 | AutoDetectDataType switchType(Object obj) { |
277 | int typeId = getTypeId(obj); |
278 | AutoDetectDataType l = last; |
279 | if (typeId != l.typeId) { |
280 | last = l = newType(typeId); |
281 | } |
282 | return l; |
283 | } |
284 | |
285 | /** |
286 | * Check whether this object is a BigInteger. |
287 | * |
288 | * @param obj the object |
289 | * @return true if yes |
290 | */ |
291 | static boolean isBigInteger(Object obj) { |
292 | return obj instanceof BigInteger && obj.getClass() == BigInteger.class; |
293 | } |
294 | |
295 | /** |
296 | * Check whether this object is a BigDecimal. |
297 | * |
298 | * @param obj the object |
299 | * @return true if yes |
300 | */ |
301 | static boolean isBigDecimal(Object obj) { |
302 | return obj instanceof BigDecimal && obj.getClass() == BigDecimal.class; |
303 | } |
304 | |
305 | /** |
306 | * Check whether this object is a date. |
307 | * |
308 | * @param obj the object |
309 | * @return true if yes |
310 | */ |
311 | static boolean isDate(Object obj) { |
312 | return obj instanceof Date && obj.getClass() == Date.class; |
313 | } |
314 | |
315 | /** |
316 | * Check whether this object is an array. |
317 | * |
318 | * @param obj the object |
319 | * @return true if yes |
320 | */ |
321 | static boolean isArray(Object obj) { |
322 | return obj != null && obj.getClass().isArray(); |
323 | } |
324 | |
325 | /** |
326 | * Get the class id, or null if not found. |
327 | * |
328 | * @param clazz the class |
329 | * @return the class id or null |
330 | */ |
331 | static Integer getCommonClassId(Class<?> clazz) { |
332 | HashMap<Class<?>, Integer> map = COMMON_CLASSES_MAP; |
333 | if (map.size() == 0) { |
334 | // lazy initialization |
335 | for (int i = 0, size = COMMON_CLASSES.length; i < size; i++) { |
336 | COMMON_CLASSES_MAP.put(COMMON_CLASSES[i], i); |
337 | } |
338 | } |
339 | return map.get(clazz); |
340 | } |
341 | |
342 | /** |
343 | * Serialize the object to a byte array. |
344 | * |
345 | * @param obj the object to serialize |
346 | * @return the byte array |
347 | */ |
348 | public static byte[] serialize(Object obj) { |
349 | try { |
350 | ByteArrayOutputStream out = new ByteArrayOutputStream(); |
351 | ObjectOutputStream os = new ObjectOutputStream(out); |
352 | os.writeObject(obj); |
353 | return out.toByteArray(); |
354 | } catch (Throwable e) { |
355 | throw DataUtils.newIllegalArgumentException( |
356 | "Could not serialize {0}", obj, e); |
357 | } |
358 | } |
359 | |
360 | /** |
361 | * De-serialize the byte array to an object. |
362 | * |
363 | * @param data the byte array |
364 | * @return the object |
365 | */ |
366 | public static Object deserialize(byte[] data) { |
367 | try { |
368 | ByteArrayInputStream in = new ByteArrayInputStream(data); |
369 | ObjectInputStream is = new ObjectInputStream(in); |
370 | return is.readObject(); |
371 | } catch (Throwable e) { |
372 | throw DataUtils.newIllegalArgumentException( |
373 | "Could not deserialize {0}", Arrays.toString(data), e); |
374 | } |
375 | } |
376 | |
377 | /** |
378 | * Compare the contents of two byte arrays. If the content or length of the |
379 | * first array is smaller than the second array, -1 is returned. If the |
380 | * content or length of the second array is smaller than the first array, 1 |
381 | * is returned. If the contents and lengths are the same, 0 is returned. |
382 | * <p> |
383 | * This method interprets bytes as unsigned. |
384 | * |
385 | * @param data1 the first byte array (must not be null) |
386 | * @param data2 the second byte array (must not be null) |
387 | * @return the result of the comparison (-1, 1 or 0) |
388 | */ |
389 | public static int compareNotNull(byte[] data1, byte[] data2) { |
390 | if (data1 == data2) { |
391 | return 0; |
392 | } |
393 | int len = Math.min(data1.length, data2.length); |
394 | for (int i = 0; i < len; i++) { |
395 | int b = data1[i] & 255; |
396 | int b2 = data2[i] & 255; |
397 | if (b != b2) { |
398 | return b > b2 ? 1 : -1; |
399 | } |
400 | } |
401 | return Integer.signum(data1.length - data2.length); |
402 | } |
403 | |
404 | /** |
405 | * The base class for auto-detect data types. |
406 | */ |
407 | abstract static class AutoDetectDataType implements DataType { |
408 | |
409 | protected final ObjectDataType base; |
410 | protected final int typeId; |
411 | |
412 | AutoDetectDataType(ObjectDataType base, int typeId) { |
413 | this.base = base; |
414 | this.typeId = typeId; |
415 | } |
416 | |
417 | @Override |
418 | public int getMemory(Object o) { |
419 | return getType(o).getMemory(o); |
420 | } |
421 | |
422 | @Override |
423 | public int compare(Object aObj, Object bObj) { |
424 | AutoDetectDataType aType = getType(aObj); |
425 | AutoDetectDataType bType = getType(bObj); |
426 | int typeDiff = aType.typeId - bType.typeId; |
427 | if (typeDiff == 0) { |
428 | return aType.compare(aObj, bObj); |
429 | } |
430 | return Integer.signum(typeDiff); |
431 | } |
432 | |
433 | @Override |
434 | public void write(WriteBuffer buff, Object[] obj, |
435 | int len, boolean key) { |
436 | for (int i = 0; i < len; i++) { |
437 | write(buff, obj[i]); |
438 | } |
439 | } |
440 | |
441 | @Override |
442 | public void write(WriteBuffer buff, Object o) { |
443 | getType(o).write(buff, o); |
444 | } |
445 | |
446 | @Override |
447 | public void read(ByteBuffer buff, Object[] obj, |
448 | int len, boolean key) { |
449 | for (int i = 0; i < len; i++) { |
450 | obj[i] = read(buff); |
451 | } |
452 | } |
453 | |
454 | @Override |
455 | public final Object read(ByteBuffer buff) { |
456 | throw DataUtils.newIllegalStateException(DataUtils.ERROR_INTERNAL, |
457 | "Internal error"); |
458 | } |
459 | |
460 | /** |
461 | * Get the type for the given object. |
462 | * |
463 | * @param o the object |
464 | * @return the type |
465 | */ |
466 | AutoDetectDataType getType(Object o) { |
467 | return base.switchType(o); |
468 | } |
469 | |
470 | /** |
471 | * Read an object from the buffer. |
472 | * |
473 | * @param buff the buffer |
474 | * @param tag the first byte of the object (usually the type) |
475 | * @return the read object |
476 | */ |
477 | abstract Object read(ByteBuffer buff, int tag); |
478 | |
479 | } |
480 | |
481 | /** |
482 | * The type for the null value |
483 | */ |
484 | static class NullType extends AutoDetectDataType { |
485 | |
486 | NullType(ObjectDataType base) { |
487 | super(base, TYPE_NULL); |
488 | } |
489 | |
490 | @Override |
491 | public int compare(Object aObj, Object bObj) { |
492 | if (aObj == null && bObj == null) { |
493 | return 0; |
494 | } else if (aObj == null) { |
495 | return -1; |
496 | } else if (bObj == null) { |
497 | return 1; |
498 | } |
499 | return super.compare(aObj, bObj); |
500 | } |
501 | |
502 | @Override |
503 | public int getMemory(Object obj) { |
504 | return obj == null ? 0 : super.getMemory(obj); |
505 | } |
506 | |
507 | @Override |
508 | public void write(WriteBuffer buff, Object obj) { |
509 | if (obj != null) { |
510 | super.write(buff, obj); |
511 | return; |
512 | } |
513 | buff.put((byte) TYPE_NULL); |
514 | } |
515 | |
516 | @Override |
517 | public Object read(ByteBuffer buff, int tag) { |
518 | return null; |
519 | } |
520 | |
521 | } |
522 | |
523 | /** |
524 | * The type for boolean true and false. |
525 | */ |
526 | static class BooleanType extends AutoDetectDataType { |
527 | |
528 | BooleanType(ObjectDataType base) { |
529 | super(base, TYPE_BOOLEAN); |
530 | } |
531 | |
532 | @Override |
533 | public int compare(Object aObj, Object bObj) { |
534 | if (aObj instanceof Boolean && bObj instanceof Boolean) { |
535 | Boolean a = (Boolean) aObj; |
536 | Boolean b = (Boolean) bObj; |
537 | return a.compareTo(b); |
538 | } |
539 | return super.compare(aObj, bObj); |
540 | } |
541 | |
542 | @Override |
543 | public int getMemory(Object obj) { |
544 | return obj instanceof Boolean ? 0 : super.getMemory(obj); |
545 | } |
546 | |
547 | @Override |
548 | public void write(WriteBuffer buff, Object obj) { |
549 | if (!(obj instanceof Boolean)) { |
550 | super.write(buff, obj); |
551 | return; |
552 | } |
553 | int tag = ((Boolean) obj) ? TAG_BOOLEAN_TRUE : TYPE_BOOLEAN; |
554 | buff.put((byte) tag); |
555 | } |
556 | |
557 | @Override |
558 | public Object read(ByteBuffer buff, int tag) { |
559 | return tag == TYPE_BOOLEAN ? Boolean.FALSE : Boolean.TRUE; |
560 | } |
561 | |
562 | } |
563 | |
564 | /** |
565 | * The type for byte objects. |
566 | */ |
567 | static class ByteType extends AutoDetectDataType { |
568 | |
569 | ByteType(ObjectDataType base) { |
570 | super(base, TYPE_BYTE); |
571 | } |
572 | |
573 | @Override |
574 | public int compare(Object aObj, Object bObj) { |
575 | if (aObj instanceof Byte && bObj instanceof Byte) { |
576 | Byte a = (Byte) aObj; |
577 | Byte b = (Byte) bObj; |
578 | return a.compareTo(b); |
579 | } |
580 | return super.compare(aObj, bObj); |
581 | } |
582 | |
583 | @Override |
584 | public int getMemory(Object obj) { |
585 | return obj instanceof Byte ? 0 : super.getMemory(obj); |
586 | } |
587 | |
588 | @Override |
589 | public void write(WriteBuffer buff, Object obj) { |
590 | if (!(obj instanceof Byte)) { |
591 | super.write(buff, obj); |
592 | return; |
593 | } |
594 | buff.put((byte) TYPE_BYTE); |
595 | buff.put(((Byte) obj).byteValue()); |
596 | } |
597 | |
598 | @Override |
599 | public Object read(ByteBuffer buff, int tag) { |
600 | return Byte.valueOf(buff.get()); |
601 | } |
602 | |
603 | } |
604 | |
605 | /** |
606 | * The type for character objects. |
607 | */ |
608 | static class CharacterType extends AutoDetectDataType { |
609 | |
610 | CharacterType(ObjectDataType base) { |
611 | super(base, TYPE_CHAR); |
612 | } |
613 | |
614 | @Override |
615 | public int compare(Object aObj, Object bObj) { |
616 | if (aObj instanceof Character && bObj instanceof Character) { |
617 | Character a = (Character) aObj; |
618 | Character b = (Character) bObj; |
619 | return a.compareTo(b); |
620 | } |
621 | return super.compare(aObj, bObj); |
622 | } |
623 | |
624 | @Override |
625 | public int getMemory(Object obj) { |
626 | return obj instanceof Character ? 24 : super.getMemory(obj); |
627 | } |
628 | |
629 | @Override |
630 | public void write(WriteBuffer buff, Object obj) { |
631 | if (!(obj instanceof Character)) { |
632 | super.write(buff, obj); |
633 | return; |
634 | } |
635 | buff.put((byte) TYPE_CHAR); |
636 | buff.putChar(((Character) obj).charValue()); |
637 | } |
638 | |
639 | @Override |
640 | public Object read(ByteBuffer buff, int tag) { |
641 | return Character.valueOf(buff.getChar()); |
642 | } |
643 | |
644 | } |
645 | |
646 | /** |
647 | * The type for short objects. |
648 | */ |
649 | static class ShortType extends AutoDetectDataType { |
650 | |
651 | ShortType(ObjectDataType base) { |
652 | super(base, TYPE_SHORT); |
653 | } |
654 | |
655 | @Override |
656 | public int compare(Object aObj, Object bObj) { |
657 | if (aObj instanceof Short && bObj instanceof Short) { |
658 | Short a = (Short) aObj; |
659 | Short b = (Short) bObj; |
660 | return a.compareTo(b); |
661 | } |
662 | return super.compare(aObj, bObj); |
663 | } |
664 | |
665 | @Override |
666 | public int getMemory(Object obj) { |
667 | return obj instanceof Short ? 24 : super.getMemory(obj); |
668 | } |
669 | |
670 | @Override |
671 | public void write(WriteBuffer buff, Object obj) { |
672 | if (!(obj instanceof Short)) { |
673 | super.write(buff, obj); |
674 | return; |
675 | } |
676 | buff.put((byte) TYPE_SHORT); |
677 | buff.putShort(((Short) obj).shortValue()); |
678 | } |
679 | |
680 | @Override |
681 | public Object read(ByteBuffer buff, int tag) { |
682 | return Short.valueOf(buff.getShort()); |
683 | } |
684 | |
685 | } |
686 | |
687 | /** |
688 | * The type for integer objects. |
689 | */ |
690 | static class IntegerType extends AutoDetectDataType { |
691 | |
692 | IntegerType(ObjectDataType base) { |
693 | super(base, TYPE_INT); |
694 | } |
695 | |
696 | @Override |
697 | public int compare(Object aObj, Object bObj) { |
698 | if (aObj instanceof Integer && bObj instanceof Integer) { |
699 | Integer a = (Integer) aObj; |
700 | Integer b = (Integer) bObj; |
701 | return a.compareTo(b); |
702 | } |
703 | return super.compare(aObj, bObj); |
704 | } |
705 | |
706 | @Override |
707 | public int getMemory(Object obj) { |
708 | return obj instanceof Integer ? 24 : super.getMemory(obj); |
709 | } |
710 | |
711 | @Override |
712 | public void write(WriteBuffer buff, Object obj) { |
713 | if (!(obj instanceof Integer)) { |
714 | super.write(buff, obj); |
715 | return; |
716 | } |
717 | int x = (Integer) obj; |
718 | if (x < 0) { |
719 | // -Integer.MIN_VALUE is smaller than 0 |
720 | if (-x < 0 || -x > DataUtils.COMPRESSED_VAR_INT_MAX) { |
721 | buff.put((byte) TAG_INTEGER_FIXED).putInt(x); |
722 | } else { |
723 | buff.put((byte) TAG_INTEGER_NEGATIVE).putVarInt(-x); |
724 | } |
725 | } else if (x <= 15) { |
726 | buff.put((byte) (TAG_INTEGER_0_15 + x)); |
727 | } else if (x <= DataUtils.COMPRESSED_VAR_INT_MAX) { |
728 | buff.put((byte) TYPE_INT).putVarInt(x); |
729 | } else { |
730 | buff.put((byte) TAG_INTEGER_FIXED).putInt(x); |
731 | } |
732 | } |
733 | |
734 | @Override |
735 | public Object read(ByteBuffer buff, int tag) { |
736 | switch (tag) { |
737 | case TYPE_INT: |
738 | return DataUtils.readVarInt(buff); |
739 | case TAG_INTEGER_NEGATIVE: |
740 | return -DataUtils.readVarInt(buff); |
741 | case TAG_INTEGER_FIXED: |
742 | return buff.getInt(); |
743 | } |
744 | return tag - TAG_INTEGER_0_15; |
745 | } |
746 | |
747 | } |
748 | |
749 | /** |
750 | * The type for long objects. |
751 | */ |
752 | static class LongType extends AutoDetectDataType { |
753 | |
754 | LongType(ObjectDataType base) { |
755 | super(base, TYPE_LONG); |
756 | } |
757 | |
758 | @Override |
759 | public int compare(Object aObj, Object bObj) { |
760 | if (aObj instanceof Long && bObj instanceof Long) { |
761 | Long a = (Long) aObj; |
762 | Long b = (Long) bObj; |
763 | return a.compareTo(b); |
764 | } |
765 | return super.compare(aObj, bObj); |
766 | } |
767 | |
768 | @Override |
769 | public int getMemory(Object obj) { |
770 | return obj instanceof Long ? 30 : super.getMemory(obj); |
771 | } |
772 | |
773 | @Override |
774 | public void write(WriteBuffer buff, Object obj) { |
775 | if (!(obj instanceof Long)) { |
776 | super.write(buff, obj); |
777 | return; |
778 | } |
779 | long x = (Long) obj; |
780 | if (x < 0) { |
781 | // -Long.MIN_VALUE is smaller than 0 |
782 | if (-x < 0 || -x > DataUtils.COMPRESSED_VAR_LONG_MAX) { |
783 | buff.put((byte) TAG_LONG_FIXED); |
784 | buff.putLong(x); |
785 | } else { |
786 | buff.put((byte) TAG_LONG_NEGATIVE); |
787 | buff.putVarLong(-x); |
788 | } |
789 | } else if (x <= 7) { |
790 | buff.put((byte) (TAG_LONG_0_7 + x)); |
791 | } else if (x <= DataUtils.COMPRESSED_VAR_LONG_MAX) { |
792 | buff.put((byte) TYPE_LONG); |
793 | buff.putVarLong(x); |
794 | } else { |
795 | buff.put((byte) TAG_LONG_FIXED); |
796 | buff.putLong(x); |
797 | } |
798 | } |
799 | |
800 | @Override |
801 | public Object read(ByteBuffer buff, int tag) { |
802 | switch (tag) { |
803 | case TYPE_LONG: |
804 | return DataUtils.readVarLong(buff); |
805 | case TAG_LONG_NEGATIVE: |
806 | return -DataUtils.readVarLong(buff); |
807 | case TAG_LONG_FIXED: |
808 | return buff.getLong(); |
809 | } |
810 | return Long.valueOf(tag - TAG_LONG_0_7); |
811 | } |
812 | |
813 | } |
814 | |
815 | /** |
816 | * The type for float objects. |
817 | */ |
818 | static class FloatType extends AutoDetectDataType { |
819 | |
820 | FloatType(ObjectDataType base) { |
821 | super(base, TYPE_FLOAT); |
822 | } |
823 | |
824 | @Override |
825 | public int compare(Object aObj, Object bObj) { |
826 | if (aObj instanceof Float && bObj instanceof Float) { |
827 | Float a = (Float) aObj; |
828 | Float b = (Float) bObj; |
829 | return a.compareTo(b); |
830 | } |
831 | return super.compare(aObj, bObj); |
832 | } |
833 | |
834 | @Override |
835 | public int getMemory(Object obj) { |
836 | return obj instanceof Float ? 24 : super.getMemory(obj); |
837 | } |
838 | |
839 | @Override |
840 | public void write(WriteBuffer buff, Object obj) { |
841 | if (!(obj instanceof Float)) { |
842 | super.write(buff, obj); |
843 | return; |
844 | } |
845 | float x = (Float) obj; |
846 | int f = Float.floatToIntBits(x); |
847 | if (f == ObjectDataType.FLOAT_ZERO_BITS) { |
848 | buff.put((byte) TAG_FLOAT_0); |
849 | } else if (f == ObjectDataType.FLOAT_ONE_BITS) { |
850 | buff.put((byte) TAG_FLOAT_1); |
851 | } else { |
852 | int value = Integer.reverse(f); |
853 | if (value >= 0 && value <= DataUtils.COMPRESSED_VAR_INT_MAX) { |
854 | buff.put((byte) TYPE_FLOAT).putVarInt(value); |
855 | } else { |
856 | buff.put((byte) TAG_FLOAT_FIXED).putFloat(x); |
857 | } |
858 | } |
859 | } |
860 | |
861 | @Override |
862 | public Object read(ByteBuffer buff, int tag) { |
863 | switch (tag) { |
864 | case TAG_FLOAT_0: |
865 | return 0f; |
866 | case TAG_FLOAT_1: |
867 | return 1f; |
868 | case TAG_FLOAT_FIXED: |
869 | return buff.getFloat(); |
870 | } |
871 | return Float.intBitsToFloat(Integer.reverse(DataUtils |
872 | .readVarInt(buff))); |
873 | } |
874 | |
875 | } |
876 | |
877 | /** |
878 | * The type for double objects. |
879 | */ |
880 | static class DoubleType extends AutoDetectDataType { |
881 | |
882 | DoubleType(ObjectDataType base) { |
883 | super(base, TYPE_DOUBLE); |
884 | } |
885 | |
886 | @Override |
887 | public int compare(Object aObj, Object bObj) { |
888 | if (aObj instanceof Double && bObj instanceof Double) { |
889 | Double a = (Double) aObj; |
890 | Double b = (Double) bObj; |
891 | return a.compareTo(b); |
892 | } |
893 | return super.compare(aObj, bObj); |
894 | } |
895 | |
896 | @Override |
897 | public int getMemory(Object obj) { |
898 | return obj instanceof Double ? 30 : super.getMemory(obj); |
899 | } |
900 | |
901 | @Override |
902 | public void write(WriteBuffer buff, Object obj) { |
903 | if (!(obj instanceof Double)) { |
904 | super.write(buff, obj); |
905 | return; |
906 | } |
907 | double x = (Double) obj; |
908 | long d = Double.doubleToLongBits(x); |
909 | if (d == ObjectDataType.DOUBLE_ZERO_BITS) { |
910 | buff.put((byte) TAG_DOUBLE_0); |
911 | } else if (d == ObjectDataType.DOUBLE_ONE_BITS) { |
912 | buff.put((byte) TAG_DOUBLE_1); |
913 | } else { |
914 | long value = Long.reverse(d); |
915 | if (value >= 0 && value <= DataUtils.COMPRESSED_VAR_LONG_MAX) { |
916 | buff.put((byte) TYPE_DOUBLE); |
917 | buff.putVarLong(value); |
918 | } else { |
919 | buff.put((byte) TAG_DOUBLE_FIXED); |
920 | buff.putDouble(x); |
921 | } |
922 | } |
923 | } |
924 | |
925 | @Override |
926 | public Object read(ByteBuffer buff, int tag) { |
927 | switch (tag) { |
928 | case TAG_DOUBLE_0: |
929 | return 0d; |
930 | case TAG_DOUBLE_1: |
931 | return 1d; |
932 | case TAG_DOUBLE_FIXED: |
933 | return buff.getDouble(); |
934 | } |
935 | return Double.longBitsToDouble(Long.reverse(DataUtils |
936 | .readVarLong(buff))); |
937 | } |
938 | |
939 | } |
940 | |
941 | /** |
942 | * The type for BigInteger objects. |
943 | */ |
944 | static class BigIntegerType extends AutoDetectDataType { |
945 | |
946 | BigIntegerType(ObjectDataType base) { |
947 | super(base, TYPE_BIG_INTEGER); |
948 | } |
949 | |
950 | @Override |
951 | public int compare(Object aObj, Object bObj) { |
952 | if (isBigInteger(aObj) && isBigInteger(bObj)) { |
953 | BigInteger a = (BigInteger) aObj; |
954 | BigInteger b = (BigInteger) bObj; |
955 | return a.compareTo(b); |
956 | } |
957 | return super.compare(aObj, bObj); |
958 | } |
959 | |
960 | @Override |
961 | public int getMemory(Object obj) { |
962 | return isBigInteger(obj) ? 100 : super.getMemory(obj); |
963 | } |
964 | |
965 | @Override |
966 | public void write(WriteBuffer buff, Object obj) { |
967 | if (!isBigInteger(obj)) { |
968 | super.write(buff, obj); |
969 | return; |
970 | } |
971 | BigInteger x = (BigInteger) obj; |
972 | if (BigInteger.ZERO.equals(x)) { |
973 | buff.put((byte) TAG_BIG_INTEGER_0); |
974 | } else if (BigInteger.ONE.equals(x)) { |
975 | buff.put((byte) TAG_BIG_INTEGER_1); |
976 | } else { |
977 | int bits = x.bitLength(); |
978 | if (bits <= 63) { |
979 | buff.put((byte) TAG_BIG_INTEGER_SMALL).putVarLong( |
980 | x.longValue()); |
981 | } else { |
982 | byte[] bytes = x.toByteArray(); |
983 | buff.put((byte) TYPE_BIG_INTEGER).putVarInt(bytes.length) |
984 | .put(bytes); |
985 | } |
986 | } |
987 | } |
988 | |
989 | @Override |
990 | public Object read(ByteBuffer buff, int tag) { |
991 | switch (tag) { |
992 | case TAG_BIG_INTEGER_0: |
993 | return BigInteger.ZERO; |
994 | case TAG_BIG_INTEGER_1: |
995 | return BigInteger.ONE; |
996 | case TAG_BIG_INTEGER_SMALL: |
997 | return BigInteger.valueOf(DataUtils.readVarLong(buff)); |
998 | } |
999 | int len = DataUtils.readVarInt(buff); |
1000 | byte[] bytes = DataUtils.newBytes(len); |
1001 | buff.get(bytes); |
1002 | return new BigInteger(bytes); |
1003 | } |
1004 | |
1005 | } |
1006 | |
1007 | /** |
1008 | * The type for BigDecimal objects. |
1009 | */ |
1010 | static class BigDecimalType extends AutoDetectDataType { |
1011 | |
1012 | BigDecimalType(ObjectDataType base) { |
1013 | super(base, TYPE_BIG_DECIMAL); |
1014 | } |
1015 | |
1016 | @Override |
1017 | public int compare(Object aObj, Object bObj) { |
1018 | if (isBigDecimal(aObj) && isBigDecimal(bObj)) { |
1019 | BigDecimal a = (BigDecimal) aObj; |
1020 | BigDecimal b = (BigDecimal) bObj; |
1021 | return a.compareTo(b); |
1022 | } |
1023 | return super.compare(aObj, bObj); |
1024 | } |
1025 | |
1026 | @Override |
1027 | public int getMemory(Object obj) { |
1028 | return isBigDecimal(obj) ? 150 : super.getMemory(obj); |
1029 | } |
1030 | |
1031 | @Override |
1032 | public void write(WriteBuffer buff, Object obj) { |
1033 | if (!isBigDecimal(obj)) { |
1034 | super.write(buff, obj); |
1035 | return; |
1036 | } |
1037 | BigDecimal x = (BigDecimal) obj; |
1038 | if (BigDecimal.ZERO.equals(x)) { |
1039 | buff.put((byte) TAG_BIG_DECIMAL_0); |
1040 | } else if (BigDecimal.ONE.equals(x)) { |
1041 | buff.put((byte) TAG_BIG_DECIMAL_1); |
1042 | } else { |
1043 | int scale = x.scale(); |
1044 | BigInteger b = x.unscaledValue(); |
1045 | int bits = b.bitLength(); |
1046 | if (bits < 64) { |
1047 | if (scale == 0) { |
1048 | buff.put((byte) TAG_BIG_DECIMAL_SMALL); |
1049 | } else { |
1050 | buff.put((byte) TAG_BIG_DECIMAL_SMALL_SCALED) |
1051 | .putVarInt(scale); |
1052 | } |
1053 | buff.putVarLong(b.longValue()); |
1054 | } else { |
1055 | byte[] bytes = b.toByteArray(); |
1056 | buff.put((byte) TYPE_BIG_DECIMAL).putVarInt(scale) |
1057 | .putVarInt(bytes.length).put(bytes); |
1058 | } |
1059 | } |
1060 | } |
1061 | |
1062 | @Override |
1063 | public Object read(ByteBuffer buff, int tag) { |
1064 | switch (tag) { |
1065 | case TAG_BIG_DECIMAL_0: |
1066 | return BigDecimal.ZERO; |
1067 | case TAG_BIG_DECIMAL_1: |
1068 | return BigDecimal.ONE; |
1069 | case TAG_BIG_DECIMAL_SMALL: |
1070 | return BigDecimal.valueOf(DataUtils.readVarLong(buff)); |
1071 | case TAG_BIG_DECIMAL_SMALL_SCALED: |
1072 | int scale = DataUtils.readVarInt(buff); |
1073 | return BigDecimal.valueOf(DataUtils.readVarLong(buff), scale); |
1074 | } |
1075 | int scale = DataUtils.readVarInt(buff); |
1076 | int len = DataUtils.readVarInt(buff); |
1077 | byte[] bytes = DataUtils.newBytes(len); |
1078 | buff.get(bytes); |
1079 | BigInteger b = new BigInteger(bytes); |
1080 | return new BigDecimal(b, scale); |
1081 | } |
1082 | |
1083 | } |
1084 | |
1085 | /** |
1086 | * The type for string objects. |
1087 | */ |
1088 | static class StringType extends AutoDetectDataType { |
1089 | |
1090 | StringType(ObjectDataType base) { |
1091 | super(base, TYPE_STRING); |
1092 | } |
1093 | |
1094 | @Override |
1095 | public int getMemory(Object obj) { |
1096 | if (!(obj instanceof String)) { |
1097 | return super.getMemory(obj); |
1098 | } |
1099 | return 24 + 2 * obj.toString().length(); |
1100 | } |
1101 | |
1102 | @Override |
1103 | public int compare(Object aObj, Object bObj) { |
1104 | if (aObj instanceof String && bObj instanceof String) { |
1105 | return aObj.toString().compareTo(bObj.toString()); |
1106 | } |
1107 | return super.compare(aObj, bObj); |
1108 | } |
1109 | |
1110 | @Override |
1111 | public void write(WriteBuffer buff, Object obj) { |
1112 | if (!(obj instanceof String)) { |
1113 | super.write(buff, obj); |
1114 | return; |
1115 | } |
1116 | String s = (String) obj; |
1117 | int len = s.length(); |
1118 | if (len <= 15) { |
1119 | buff.put((byte) (TAG_STRING_0_15 + len)); |
1120 | } else { |
1121 | buff.put((byte) TYPE_STRING).putVarInt(len); |
1122 | } |
1123 | buff.putStringData(s, len); |
1124 | } |
1125 | |
1126 | @Override |
1127 | public Object read(ByteBuffer buff, int tag) { |
1128 | int len; |
1129 | if (tag == TYPE_STRING) { |
1130 | len = DataUtils.readVarInt(buff); |
1131 | } else { |
1132 | len = tag - TAG_STRING_0_15; |
1133 | } |
1134 | return DataUtils.readString(buff, len); |
1135 | } |
1136 | |
1137 | } |
1138 | |
1139 | /** |
1140 | * The type for UUID objects. |
1141 | */ |
1142 | static class UUIDType extends AutoDetectDataType { |
1143 | |
1144 | UUIDType(ObjectDataType base) { |
1145 | super(base, TYPE_UUID); |
1146 | } |
1147 | |
1148 | @Override |
1149 | public int getMemory(Object obj) { |
1150 | return obj instanceof UUID ? 40 : super.getMemory(obj); |
1151 | } |
1152 | |
1153 | @Override |
1154 | public int compare(Object aObj, Object bObj) { |
1155 | if (aObj instanceof UUID && bObj instanceof UUID) { |
1156 | UUID a = (UUID) aObj; |
1157 | UUID b = (UUID) bObj; |
1158 | return a.compareTo(b); |
1159 | } |
1160 | return super.compare(aObj, bObj); |
1161 | } |
1162 | |
1163 | @Override |
1164 | public void write(WriteBuffer buff, Object obj) { |
1165 | if (!(obj instanceof UUID)) { |
1166 | super.write(buff, obj); |
1167 | return; |
1168 | } |
1169 | buff.put((byte) TYPE_UUID); |
1170 | UUID a = (UUID) obj; |
1171 | buff.putLong(a.getMostSignificantBits()); |
1172 | buff.putLong(a.getLeastSignificantBits()); |
1173 | } |
1174 | |
1175 | @Override |
1176 | public Object read(ByteBuffer buff, int tag) { |
1177 | long a = buff.getLong(), b = buff.getLong(); |
1178 | return new UUID(a, b); |
1179 | } |
1180 | |
1181 | } |
1182 | |
1183 | /** |
1184 | * The type for java.util.Date objects. |
1185 | */ |
1186 | static class DateType extends AutoDetectDataType { |
1187 | |
1188 | DateType(ObjectDataType base) { |
1189 | super(base, TYPE_DATE); |
1190 | } |
1191 | |
1192 | @Override |
1193 | public int getMemory(Object obj) { |
1194 | return isDate(obj) ? 40 : super.getMemory(obj); |
1195 | } |
1196 | |
1197 | @Override |
1198 | public int compare(Object aObj, Object bObj) { |
1199 | if (isDate(aObj) && isDate(bObj)) { |
1200 | Date a = (Date) aObj; |
1201 | Date b = (Date) bObj; |
1202 | return a.compareTo(b); |
1203 | } |
1204 | return super.compare(aObj, bObj); |
1205 | } |
1206 | |
1207 | @Override |
1208 | public void write(WriteBuffer buff, Object obj) { |
1209 | if (!isDate(obj)) { |
1210 | super.write(buff, obj); |
1211 | return; |
1212 | } |
1213 | buff.put((byte) TYPE_DATE); |
1214 | Date a = (Date) obj; |
1215 | buff.putLong(a.getTime()); |
1216 | } |
1217 | |
1218 | @Override |
1219 | public Object read(ByteBuffer buff, int tag) { |
1220 | long a = buff.getLong(); |
1221 | return new Date(a); |
1222 | } |
1223 | |
1224 | } |
1225 | |
1226 | /** |
1227 | * The type for object arrays. |
1228 | */ |
1229 | static class ObjectArrayType extends AutoDetectDataType { |
1230 | |
1231 | private final ObjectDataType elementType = new ObjectDataType(); |
1232 | |
1233 | ObjectArrayType(ObjectDataType base) { |
1234 | super(base, TYPE_ARRAY); |
1235 | } |
1236 | |
1237 | @Override |
1238 | public int getMemory(Object obj) { |
1239 | if (!isArray(obj)) { |
1240 | return super.getMemory(obj); |
1241 | } |
1242 | int size = 64; |
1243 | Class<?> type = obj.getClass().getComponentType(); |
1244 | if (type.isPrimitive()) { |
1245 | int len = Array.getLength(obj); |
1246 | if (type == boolean.class) { |
1247 | size += len; |
1248 | } else if (type == byte.class) { |
1249 | size += len; |
1250 | } else if (type == char.class) { |
1251 | size += len * 2; |
1252 | } else if (type == short.class) { |
1253 | size += len * 2; |
1254 | } else if (type == int.class) { |
1255 | size += len * 4; |
1256 | } else if (type == float.class) { |
1257 | size += len * 4; |
1258 | } else if (type == double.class) { |
1259 | size += len * 8; |
1260 | } else if (type == long.class) { |
1261 | size += len * 8; |
1262 | } |
1263 | } else { |
1264 | for (Object x : (Object[]) obj) { |
1265 | if (x != null) { |
1266 | size += elementType.getMemory(x); |
1267 | } |
1268 | } |
1269 | } |
1270 | // we say they are larger, because these objects |
1271 | // use quite a lot of disk space |
1272 | return size * 2; |
1273 | } |
1274 | |
1275 | @Override |
1276 | public int compare(Object aObj, Object bObj) { |
1277 | if (!isArray(aObj) || !isArray(bObj)) { |
1278 | return super.compare(aObj, bObj); |
1279 | } |
1280 | if (aObj == bObj) { |
1281 | return 0; |
1282 | } |
1283 | Class<?> type = aObj.getClass().getComponentType(); |
1284 | Class<?> bType = bObj.getClass().getComponentType(); |
1285 | if (type != bType) { |
1286 | Integer classA = getCommonClassId(type); |
1287 | Integer classB = getCommonClassId(bType); |
1288 | if (classA != null) { |
1289 | if (classB != null) { |
1290 | return classA.compareTo(classB); |
1291 | } |
1292 | return -1; |
1293 | } else if (classB != null) { |
1294 | return 1; |
1295 | } |
1296 | return type.getName().compareTo(bType.getName()); |
1297 | } |
1298 | int aLen = Array.getLength(aObj); |
1299 | int bLen = Array.getLength(bObj); |
1300 | int len = Math.min(aLen, bLen); |
1301 | if (type.isPrimitive()) { |
1302 | if (type == byte.class) { |
1303 | byte[] a = (byte[]) aObj; |
1304 | byte[] b = (byte[]) bObj; |
1305 | return compareNotNull(a, b); |
1306 | } |
1307 | for (int i = 0; i < len; i++) { |
1308 | int x; |
1309 | if (type == boolean.class) { |
1310 | x = Integer.signum((((boolean[]) aObj)[i] ? 1 : 0) |
1311 | - (((boolean[]) bObj)[i] ? 1 : 0)); |
1312 | } else if (type == char.class) { |
1313 | x = Integer.signum((((char[]) aObj)[i]) |
1314 | - (((char[]) bObj)[i])); |
1315 | } else if (type == short.class) { |
1316 | x = Integer.signum((((short[]) aObj)[i]) |
1317 | - (((short[]) bObj)[i])); |
1318 | } else if (type == int.class) { |
1319 | int a = ((int[]) aObj)[i]; |
1320 | int b = ((int[]) bObj)[i]; |
1321 | x = a == b ? 0 : a < b ? -1 : 1; |
1322 | } else if (type == float.class) { |
1323 | x = Float.compare(((float[]) aObj)[i], |
1324 | ((float[]) bObj)[i]); |
1325 | } else if (type == double.class) { |
1326 | x = Double.compare(((double[]) aObj)[i], |
1327 | ((double[]) bObj)[i]); |
1328 | } else { |
1329 | long a = ((long[]) aObj)[i]; |
1330 | long b = ((long[]) bObj)[i]; |
1331 | x = a == b ? 0 : a < b ? -1 : 1; |
1332 | } |
1333 | if (x != 0) { |
1334 | return x; |
1335 | } |
1336 | } |
1337 | } else { |
1338 | Object[] a = (Object[]) aObj; |
1339 | Object[] b = (Object[]) bObj; |
1340 | for (int i = 0; i < len; i++) { |
1341 | int comp = elementType.compare(a[i], b[i]); |
1342 | if (comp != 0) { |
1343 | return comp; |
1344 | } |
1345 | } |
1346 | } |
1347 | return aLen == bLen ? 0 : aLen < bLen ? -1 : 1; |
1348 | } |
1349 | |
1350 | @Override |
1351 | public void write(WriteBuffer buff, Object obj) { |
1352 | if (!isArray(obj)) { |
1353 | super.write(buff, obj); |
1354 | return; |
1355 | } |
1356 | Class<?> type = obj.getClass().getComponentType(); |
1357 | Integer classId = getCommonClassId(type); |
1358 | if (classId != null) { |
1359 | if (type.isPrimitive()) { |
1360 | if (type == byte.class) { |
1361 | byte[] data = (byte[]) obj; |
1362 | int len = data.length; |
1363 | if (len <= 15) { |
1364 | buff.put((byte) (TAG_BYTE_ARRAY_0_15 + len)); |
1365 | } else { |
1366 | buff.put((byte) TYPE_ARRAY) |
1367 | .put((byte) classId.intValue()) |
1368 | .putVarInt(len); |
1369 | } |
1370 | buff.put(data); |
1371 | return; |
1372 | } |
1373 | int len = Array.getLength(obj); |
1374 | buff.put((byte) TYPE_ARRAY).put((byte) classId.intValue()) |
1375 | .putVarInt(len); |
1376 | for (int i = 0; i < len; i++) { |
1377 | if (type == boolean.class) { |
1378 | buff.put((byte) (((boolean[]) obj)[i] ? 1 : 0)); |
1379 | } else if (type == char.class) { |
1380 | buff.putChar(((char[]) obj)[i]); |
1381 | } else if (type == short.class) { |
1382 | buff.putShort(((short[]) obj)[i]); |
1383 | } else if (type == int.class) { |
1384 | buff.putInt(((int[]) obj)[i]); |
1385 | } else if (type == float.class) { |
1386 | buff.putFloat(((float[]) obj)[i]); |
1387 | } else if (type == double.class) { |
1388 | buff.putDouble(((double[]) obj)[i]); |
1389 | } else { |
1390 | buff.putLong(((long[]) obj)[i]); |
1391 | } |
1392 | } |
1393 | return; |
1394 | } |
1395 | buff.put((byte) TYPE_ARRAY).put((byte) classId.intValue()); |
1396 | } else { |
1397 | buff.put((byte) TYPE_ARRAY).put((byte) -1); |
1398 | String c = type.getName(); |
1399 | StringDataType.INSTANCE.write(buff, c); |
1400 | } |
1401 | Object[] array = (Object[]) obj; |
1402 | int len = array.length; |
1403 | buff.putVarInt(len); |
1404 | for (Object x : array) { |
1405 | elementType.write(buff, x); |
1406 | } |
1407 | } |
1408 | |
1409 | @Override |
1410 | public Object read(ByteBuffer buff, int tag) { |
1411 | if (tag != TYPE_ARRAY) { |
1412 | byte[] data; |
1413 | int len = tag - TAG_BYTE_ARRAY_0_15; |
1414 | data = DataUtils.newBytes(len); |
1415 | buff.get(data); |
1416 | return data; |
1417 | } |
1418 | int ct = buff.get(); |
1419 | Class<?> clazz; |
1420 | Object obj; |
1421 | if (ct == -1) { |
1422 | String componentType = StringDataType.INSTANCE.read(buff); |
1423 | try { |
1424 | clazz = Class.forName(componentType); |
1425 | } catch (Exception e) { |
1426 | throw DataUtils.newIllegalStateException( |
1427 | DataUtils.ERROR_SERIALIZATION, |
1428 | "Could not get class {0}", componentType, e); |
1429 | } |
1430 | } else { |
1431 | clazz = COMMON_CLASSES[ct]; |
1432 | } |
1433 | int len = DataUtils.readVarInt(buff); |
1434 | try { |
1435 | obj = Array.newInstance(clazz, len); |
1436 | } catch (Exception e) { |
1437 | throw DataUtils.newIllegalStateException( |
1438 | DataUtils.ERROR_SERIALIZATION, |
1439 | "Could not create array of type {0} length {1}", clazz, |
1440 | len, e); |
1441 | } |
1442 | if (clazz.isPrimitive()) { |
1443 | for (int i = 0; i < len; i++) { |
1444 | if (clazz == boolean.class) { |
1445 | ((boolean[]) obj)[i] = buff.get() == 1; |
1446 | } else if (clazz == byte.class) { |
1447 | ((byte[]) obj)[i] = buff.get(); |
1448 | } else if (clazz == char.class) { |
1449 | ((char[]) obj)[i] = buff.getChar(); |
1450 | } else if (clazz == short.class) { |
1451 | ((short[]) obj)[i] = buff.getShort(); |
1452 | } else if (clazz == int.class) { |
1453 | ((int[]) obj)[i] = buff.getInt(); |
1454 | } else if (clazz == float.class) { |
1455 | ((float[]) obj)[i] = buff.getFloat(); |
1456 | } else if (clazz == double.class) { |
1457 | ((double[]) obj)[i] = buff.getDouble(); |
1458 | } else { |
1459 | ((long[]) obj)[i] = buff.getLong(); |
1460 | } |
1461 | } |
1462 | } else { |
1463 | Object[] array = (Object[]) obj; |
1464 | for (int i = 0; i < len; i++) { |
1465 | array[i] = elementType.read(buff); |
1466 | } |
1467 | } |
1468 | return obj; |
1469 | } |
1470 | |
1471 | } |
1472 | |
1473 | /** |
1474 | * The type for serialized objects. |
1475 | */ |
1476 | static class SerializedObjectType extends AutoDetectDataType { |
1477 | |
1478 | private int averageSize = 10000; |
1479 | |
1480 | SerializedObjectType(ObjectDataType base) { |
1481 | super(base, TYPE_SERIALIZED_OBJECT); |
1482 | } |
1483 | |
1484 | @SuppressWarnings("unchecked") |
1485 | @Override |
1486 | public int compare(Object aObj, Object bObj) { |
1487 | if (aObj == bObj) { |
1488 | return 0; |
1489 | } |
1490 | DataType ta = getType(aObj); |
1491 | DataType tb = getType(bObj); |
1492 | if (ta != this || tb != this) { |
1493 | if (ta == tb) { |
1494 | return ta.compare(aObj, bObj); |
1495 | } |
1496 | return super.compare(aObj, bObj); |
1497 | } |
1498 | // TODO ensure comparable type (both may be comparable but not |
1499 | // with each other) |
1500 | if (aObj instanceof Comparable) { |
1501 | if (aObj.getClass().isAssignableFrom(bObj.getClass())) { |
1502 | return ((Comparable<Object>) aObj).compareTo(bObj); |
1503 | } |
1504 | } |
1505 | if (bObj instanceof Comparable) { |
1506 | if (bObj.getClass().isAssignableFrom(aObj.getClass())) { |
1507 | return -((Comparable<Object>) bObj).compareTo(aObj); |
1508 | } |
1509 | } |
1510 | byte[] a = serialize(aObj); |
1511 | byte[] b = serialize(bObj); |
1512 | return compareNotNull(a, b); |
1513 | } |
1514 | |
1515 | @Override |
1516 | public int getMemory(Object obj) { |
1517 | DataType t = getType(obj); |
1518 | if (t == this) { |
1519 | return averageSize; |
1520 | } |
1521 | return t.getMemory(obj); |
1522 | } |
1523 | |
1524 | @Override |
1525 | public void write(WriteBuffer buff, Object obj) { |
1526 | DataType t = getType(obj); |
1527 | if (t != this) { |
1528 | t.write(buff, obj); |
1529 | return; |
1530 | } |
1531 | byte[] data = serialize(obj); |
1532 | // we say they are larger, because these objects |
1533 | // use quite a lot of disk space |
1534 | int size = data.length * 2; |
1535 | // adjust the average size |
1536 | // using an exponential moving average |
1537 | averageSize = (size + 15 * averageSize) / 16; |
1538 | buff.put((byte) TYPE_SERIALIZED_OBJECT).putVarInt(data.length) |
1539 | .put(data); |
1540 | } |
1541 | |
1542 | @Override |
1543 | public Object read(ByteBuffer buff, int tag) { |
1544 | int len = DataUtils.readVarInt(buff); |
1545 | byte[] data = DataUtils.newBytes(len); |
1546 | buff.get(data); |
1547 | return deserialize(data); |
1548 | } |
1549 | |
1550 | } |
1551 | |
1552 | } |