1 package com.fasterxml.jackson.databind.util; 2 3 import java.lang.reflect.Array; 4 import java.util.*; 5 6 /** 7 * Helper class that contains set of distinct builders for different 8 * arrays of primitive values. It also provides trivially simple 9 * reuse scheme, which assumes that caller knows not to use instances 10 * concurrently (which works ok with primitive arrays since they can 11 * not contain other non-primitive types). 12 * Also note that instances are not thread safe; the intent is that 13 * a builder is constructed on per-call (deserialization) basis. 14 */ 15 public final class ArrayBuilders 16 { 17 private BooleanBuilder _booleanBuilder = null; 18 19 // note: no need for char[] builder, assume they are Strings 20 21 private ByteBuilder _byteBuilder = null; 22 private ShortBuilder _shortBuilder = null; 23 private IntBuilder _intBuilder = null; 24 private LongBuilder _longBuilder = null; 25 26 private FloatBuilder _floatBuilder = null; 27 private DoubleBuilder _doubleBuilder = null; 28 ArrayBuilders()29 public ArrayBuilders() { } 30 getBooleanBuilder()31 public BooleanBuilder getBooleanBuilder() 32 { 33 if (_booleanBuilder == null) { 34 _booleanBuilder = new BooleanBuilder(); 35 } 36 return _booleanBuilder; 37 } 38 getByteBuilder()39 public ByteBuilder getByteBuilder() 40 { 41 if (_byteBuilder == null) { 42 _byteBuilder = new ByteBuilder(); 43 } 44 return _byteBuilder; 45 } getShortBuilder()46 public ShortBuilder getShortBuilder() 47 { 48 if (_shortBuilder == null) { 49 _shortBuilder = new ShortBuilder(); 50 } 51 return _shortBuilder; 52 } getIntBuilder()53 public IntBuilder getIntBuilder() 54 { 55 if (_intBuilder == null) { 56 _intBuilder = new IntBuilder(); 57 } 58 return _intBuilder; 59 } getLongBuilder()60 public LongBuilder getLongBuilder() 61 { 62 if (_longBuilder == null) { 63 _longBuilder = new LongBuilder(); 64 } 65 return _longBuilder; 66 } 67 getFloatBuilder()68 public FloatBuilder getFloatBuilder() 69 { 70 if (_floatBuilder == null) { 71 _floatBuilder = new FloatBuilder(); 72 } 73 return _floatBuilder; 74 } getDoubleBuilder()75 public DoubleBuilder getDoubleBuilder() 76 { 77 if (_doubleBuilder == null) { 78 _doubleBuilder = new DoubleBuilder(); 79 } 80 return _doubleBuilder; 81 } 82 83 /* 84 /********************************************************** 85 /* Impl classes 86 /********************************************************** 87 */ 88 89 public final static class BooleanBuilder 90 extends PrimitiveArrayBuilder<boolean[]> 91 { BooleanBuilder()92 public BooleanBuilder() { } 93 @Override _constructArray(int len)94 public final boolean[] _constructArray(int len) { return new boolean[len]; } 95 } 96 97 public final static class ByteBuilder 98 extends PrimitiveArrayBuilder<byte[]> 99 { ByteBuilder()100 public ByteBuilder() { } 101 @Override _constructArray(int len)102 public final byte[] _constructArray(int len) { return new byte[len]; } 103 } 104 public final static class ShortBuilder 105 extends PrimitiveArrayBuilder<short[]> 106 { ShortBuilder()107 public ShortBuilder() { } 108 @Override _constructArray(int len)109 public final short[] _constructArray(int len) { return new short[len]; } 110 } 111 public final static class IntBuilder 112 extends PrimitiveArrayBuilder<int[]> 113 { IntBuilder()114 public IntBuilder() { } 115 @Override _constructArray(int len)116 public final int[] _constructArray(int len) { return new int[len]; } 117 } 118 public final static class LongBuilder 119 extends PrimitiveArrayBuilder<long[]> 120 { LongBuilder()121 public LongBuilder() { } 122 @Override _constructArray(int len)123 public final long[] _constructArray(int len) { return new long[len]; } 124 } 125 126 public final static class FloatBuilder 127 extends PrimitiveArrayBuilder<float[]> 128 { FloatBuilder()129 public FloatBuilder() { } 130 @Override _constructArray(int len)131 public final float[] _constructArray(int len) { return new float[len]; } 132 } 133 public final static class DoubleBuilder 134 extends PrimitiveArrayBuilder<double[]> 135 { DoubleBuilder()136 public DoubleBuilder() { } 137 @Override _constructArray(int len)138 public final double[] _constructArray(int len) { return new double[len]; } 139 } 140 141 /* 142 /********************************************************** 143 /* Static helper methods 144 /********************************************************** 145 */ 146 147 /** 148 * Helper method used for constructing simple value comparator used for 149 * comparing arrays for content equality. 150 *<p> 151 * Note: current implementation is not optimized for speed; if performance 152 * ever becomes an issue, it is possible to construct much more efficient 153 * typed instances (one for Object[] and sub-types; one per primitive type). 154 * 155 * @since 2.2 Moved from earlier <code>Comparators</code> class 156 */ getArrayComparator(final Object defaultValue)157 public static Object getArrayComparator(final Object defaultValue) 158 { 159 final int length = Array.getLength(defaultValue); 160 final Class<?> defaultValueType = defaultValue.getClass(); 161 return new Object() { 162 @Override 163 public boolean equals(Object other) { 164 if (other == this) return true; 165 if (!ClassUtil.hasClass(other, defaultValueType)) { 166 return false; 167 } 168 if (Array.getLength(other) != length) return false; 169 // so far so good: compare actual equality; but only shallow one 170 for (int i = 0; i < length; ++i) { 171 Object value1 = Array.get(defaultValue, i); 172 Object value2 = Array.get(other, i); 173 if (value1 == value2) continue; 174 if (value1 != null) { 175 if (!value1.equals(value2)) { 176 return false; 177 } 178 } 179 } 180 return true; 181 } 182 }; 183 } 184 185 public static <T> HashSet<T> arrayToSet(T[] elements) 186 { 187 if (elements != null) { 188 int len = elements.length; 189 HashSet<T> result = new HashSet<T>(len); 190 for (int i = 0; i < len; ++i) { 191 result.add(elements[i]); 192 } 193 return result; 194 } 195 return new HashSet<T>(); 196 } 197 198 /** 199 * Helper method for constructing a new array that contains specified 200 * element followed by contents of the given array but never contains 201 * duplicates. 202 * If element already existed, one of two things happens: if the element 203 * was already the first one in array, array is returned as is; but 204 * if not, a new copy is created in which element has moved as the head. 205 */ 206 @SuppressWarnings("unchecked") 207 public static <T> T[] insertInListNoDup(T[] array, T element) 208 { 209 final int len = array.length; 210 211 // First: see if the element already exists 212 for (int ix = 0; ix < len; ++ix) { 213 if (array[ix] == element) { 214 // if at head already, return as is 215 if (ix == 0) { 216 return array; 217 } 218 // otherwise move things around 219 T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), len); 220 System.arraycopy(array, 0, result, 1, ix); 221 result[0] = element; 222 ++ix; 223 int left = len - ix; 224 if (left > 0) { 225 System.arraycopy(array, ix, result, ix, left); 226 } 227 return result; 228 } 229 } 230 231 // but if not, allocate new array, move 232 T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), len+1); 233 if (len > 0) { 234 System.arraycopy(array, 0, result, 1, len); 235 } 236 result[0] = element; 237 return result; 238 } 239 } 240