1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal;
18
19 import java.lang.reflect.Array;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.IdentityHashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.commons.jexl3.JexlArithmetic;
27 import org.apache.commons.jexl3.internal.introspection.ClassMisc;
28
29
30
31
32 public class ArrayBuilder implements JexlArithmetic.ArrayBuilder {
33
34 private static final int PRIMITIVE_SIZE = 8;
35
36 private static final Map<Class<?>, Class<?>> BOXING_CLASSES;
37 static {
38 BOXING_CLASSES = new IdentityHashMap<>(PRIMITIVE_SIZE);
39 BOXING_CLASSES.put(Boolean.class, Boolean.TYPE);
40 BOXING_CLASSES.put(Byte.class, Byte.TYPE);
41 BOXING_CLASSES.put(Character.class, Character.TYPE);
42 BOXING_CLASSES.put(Double.class, Double.TYPE);
43 BOXING_CLASSES.put(Float.class, Float.TYPE);
44 BOXING_CLASSES.put(Integer.class, Integer.TYPE);
45 BOXING_CLASSES.put(Long.class, Long.TYPE);
46 BOXING_CLASSES.put(Short.class, Short.TYPE);
47 }
48
49
50
51
52
53
54 protected static Class<?> unboxingClass(final Class<?> parm) {
55 return BOXING_CLASSES.getOrDefault(parm, parm);
56 }
57
58
59 protected Class<?> commonClass;
60
61 protected boolean isNumber = true;
62
63 protected boolean unboxing = true;
64
65 protected final Object[] untyped;
66
67 protected int added;
68
69 protected final boolean extended;
70
71
72
73
74
75 public ArrayBuilder(final int size) {
76 this(size, false);
77 }
78
79
80
81
82
83
84 public ArrayBuilder(final int size, final boolean extended) {
85 this.untyped = new Object[size];
86 this.extended = extended;
87 }
88 @Override
89 public void add(final Object value) {
90
91 if (!Object.class.equals(commonClass)) {
92 if (value == null) {
93 isNumber = false;
94 unboxing = false;
95 } else {
96 final Class<?> eclass = value.getClass();
97
98 if (commonClass == null) {
99 commonClass = eclass;
100 isNumber = isNumber && Number.class.isAssignableFrom(commonClass);
101 } else if (!commonClass.isAssignableFrom(eclass)) {
102
103 if (isNumber && Number.class.isAssignableFrom(eclass)) {
104 commonClass = Number.class;
105 } else {
106 isNumber = false;
107 commonClass = getCommonSuperClass(commonClass, eclass);
108 }
109 }
110 }
111 }
112 if (added >= untyped.length) {
113 throw new IllegalArgumentException("add() over size");
114 }
115 untyped[added++] = value;
116 }
117
118 @Override
119 public Object create(final boolean e) {
120 if (untyped == null) {
121 return new Object[0];
122 }
123 final int size = added;
124 if (extended || e) {
125 final List<Object> list = newList(commonClass, size);
126 list.addAll(Arrays.asList(untyped).subList(0, size));
127 return list;
128 }
129
130 if (commonClass == null || Object.class.equals(commonClass)) {
131 return untyped.clone();
132 }
133
134 if (unboxing) {
135 commonClass = unboxingClass(commonClass);
136 }
137
138 final Object typed = Array.newInstance(commonClass, size);
139 for (int i = 0; i < size; ++i) {
140 Array.set(typed, i, untyped[i]);
141 }
142 return typed;
143 }
144
145
146
147
148
149
150
151
152 protected Class<?> getCommonSuperClass(final Class<?> baseClass, final Class<?> other) {
153 return ClassMisc.getCommonSuperClass(baseClass, other);
154 }
155
156
157
158
159
160
161
162
163 protected <T> List<T> newList(final Class<? extends T> clazz, final int size) {
164 return new ArrayList<>(size);
165 }
166 }