xref: /aosp_15_r20/external/jackson-databind/attic/ContainerBuilder.java (revision 0ed15c778abdfe0f5f51f6133673e1619d6e56e4)
1*0ed15c77SAndroid Build Coastguard Worker package com.fasterxml.jackson.databind.util;
2*0ed15c77SAndroid Build Coastguard Worker 
3*0ed15c77SAndroid Build Coastguard Worker import java.lang.reflect.Array;
4*0ed15c77SAndroid Build Coastguard Worker import java.util.*;
5*0ed15c77SAndroid Build Coastguard Worker 
6*0ed15c77SAndroid Build Coastguard Worker /**
7*0ed15c77SAndroid Build Coastguard Worker  * Helper class used for constructing "untyped" {@link java.util.List},
8*0ed15c77SAndroid Build Coastguard Worker  * {@link java.util.Map} and <code>Object[]</code> values.
9*0ed15c77SAndroid Build Coastguard Worker  * Could help performance if a single instance can be used for building
10*0ed15c77SAndroid Build Coastguard Worker  * nested Maps, Lists/Object[] of relatively small size.
11*0ed15c77SAndroid Build Coastguard Worker  * Whether use makes sense depends; currently this class is not used.
12*0ed15c77SAndroid Build Coastguard Worker  */
13*0ed15c77SAndroid Build Coastguard Worker public final class ContainerBuilder
14*0ed15c77SAndroid Build Coastguard Worker {
15*0ed15c77SAndroid Build Coastguard Worker     private final static int MAX_BUF = 1000;
16*0ed15c77SAndroid Build Coastguard Worker 
17*0ed15c77SAndroid Build Coastguard Worker     /**
18*0ed15c77SAndroid Build Coastguard Worker      * Buffer in which contents are being buffered (except for cases where
19*0ed15c77SAndroid Build Coastguard Worker      * size has grown too big to bother with separate buffer)
20*0ed15c77SAndroid Build Coastguard Worker      */
21*0ed15c77SAndroid Build Coastguard Worker     private Object[] b;
22*0ed15c77SAndroid Build Coastguard Worker 
23*0ed15c77SAndroid Build Coastguard Worker     /**
24*0ed15c77SAndroid Build Coastguard Worker      * Pointer to the next available slot in temporary buffer.
25*0ed15c77SAndroid Build Coastguard Worker      */
26*0ed15c77SAndroid Build Coastguard Worker     private int tail;
27*0ed15c77SAndroid Build Coastguard Worker 
28*0ed15c77SAndroid Build Coastguard Worker     /**
29*0ed15c77SAndroid Build Coastguard Worker      * When building potentially multiple containers, we need to keep track of
30*0ed15c77SAndroid Build Coastguard Worker      * the starting pointer for the current container.
31*0ed15c77SAndroid Build Coastguard Worker      */
32*0ed15c77SAndroid Build Coastguard Worker     private int start;
33*0ed15c77SAndroid Build Coastguard Worker 
34*0ed15c77SAndroid Build Coastguard Worker     /**
35*0ed15c77SAndroid Build Coastguard Worker      * In cases where size of buffered contents has grown big enough that buffering
36*0ed15c77SAndroid Build Coastguard Worker      * does not make sense, an actual {@link java.util.List} will be constructed
37*0ed15c77SAndroid Build Coastguard Worker      * earlier and used instead of buffering.
38*0ed15c77SAndroid Build Coastguard Worker      */
39*0ed15c77SAndroid Build Coastguard Worker     private List<Object> list;
40*0ed15c77SAndroid Build Coastguard Worker 
41*0ed15c77SAndroid Build Coastguard Worker     /**
42*0ed15c77SAndroid Build Coastguard Worker      * Similar to <code>list</code>, we may sometimes eagerly construct result
43*0ed15c77SAndroid Build Coastguard Worker      * {@link java.util.Map} and skip actual buffering.
44*0ed15c77SAndroid Build Coastguard Worker      */
45*0ed15c77SAndroid Build Coastguard Worker     private Map<String,Object> map;
46*0ed15c77SAndroid Build Coastguard Worker 
ContainerBuilder(int bufSize)47*0ed15c77SAndroid Build Coastguard Worker     public ContainerBuilder(int bufSize) {
48*0ed15c77SAndroid Build Coastguard Worker         b = new Object[bufSize & ~1];
49*0ed15c77SAndroid Build Coastguard Worker     }
50*0ed15c77SAndroid Build Coastguard Worker 
canReuse()51*0ed15c77SAndroid Build Coastguard Worker     public boolean canReuse() {
52*0ed15c77SAndroid Build Coastguard Worker         return (list == null) && (map == null);
53*0ed15c77SAndroid Build Coastguard Worker     }
54*0ed15c77SAndroid Build Coastguard Worker 
bufferLength()55*0ed15c77SAndroid Build Coastguard Worker     public int bufferLength() {
56*0ed15c77SAndroid Build Coastguard Worker         return b.length;
57*0ed15c77SAndroid Build Coastguard Worker     }
58*0ed15c77SAndroid Build Coastguard Worker 
59*0ed15c77SAndroid Build Coastguard Worker     /*
60*0ed15c77SAndroid Build Coastguard Worker     /**********************************************************
61*0ed15c77SAndroid Build Coastguard Worker     /* Public API
62*0ed15c77SAndroid Build Coastguard Worker     /**********************************************************
63*0ed15c77SAndroid Build Coastguard Worker      */
64*0ed15c77SAndroid Build Coastguard Worker 
start()65*0ed15c77SAndroid Build Coastguard Worker     public int start() {
66*0ed15c77SAndroid Build Coastguard Worker         if (list != null || map != null) {
67*0ed15c77SAndroid Build Coastguard Worker             throw new IllegalStateException();
68*0ed15c77SAndroid Build Coastguard Worker         }
69*0ed15c77SAndroid Build Coastguard Worker         final int prevStart = start;
70*0ed15c77SAndroid Build Coastguard Worker         start = tail;
71*0ed15c77SAndroid Build Coastguard Worker         return prevStart;
72*0ed15c77SAndroid Build Coastguard Worker     }
73*0ed15c77SAndroid Build Coastguard Worker 
startList(Object value)74*0ed15c77SAndroid Build Coastguard Worker     public int startList(Object value) {
75*0ed15c77SAndroid Build Coastguard Worker         if (list != null || map != null) {
76*0ed15c77SAndroid Build Coastguard Worker             throw new IllegalStateException();
77*0ed15c77SAndroid Build Coastguard Worker         }
78*0ed15c77SAndroid Build Coastguard Worker         final int prevStart = start;
79*0ed15c77SAndroid Build Coastguard Worker         start = tail;
80*0ed15c77SAndroid Build Coastguard Worker         add(value);
81*0ed15c77SAndroid Build Coastguard Worker         return prevStart;
82*0ed15c77SAndroid Build Coastguard Worker     }
83*0ed15c77SAndroid Build Coastguard Worker 
startMap(String key, Object value)84*0ed15c77SAndroid Build Coastguard Worker     public int startMap(String key, Object value) {
85*0ed15c77SAndroid Build Coastguard Worker         if (list != null || map != null) {
86*0ed15c77SAndroid Build Coastguard Worker             throw new IllegalStateException();
87*0ed15c77SAndroid Build Coastguard Worker         }
88*0ed15c77SAndroid Build Coastguard Worker         final int prevStart = start;
89*0ed15c77SAndroid Build Coastguard Worker         start = tail;
90*0ed15c77SAndroid Build Coastguard Worker         put(key, value);
91*0ed15c77SAndroid Build Coastguard Worker         return prevStart;
92*0ed15c77SAndroid Build Coastguard Worker     }
93*0ed15c77SAndroid Build Coastguard Worker 
add(Object value)94*0ed15c77SAndroid Build Coastguard Worker     public void add(Object value) {
95*0ed15c77SAndroid Build Coastguard Worker         if (list != null) {
96*0ed15c77SAndroid Build Coastguard Worker             list.add(value);
97*0ed15c77SAndroid Build Coastguard Worker         } else if (tail >= b.length) {
98*0ed15c77SAndroid Build Coastguard Worker             _expandList(value);
99*0ed15c77SAndroid Build Coastguard Worker         } else {
100*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = value;
101*0ed15c77SAndroid Build Coastguard Worker         }
102*0ed15c77SAndroid Build Coastguard Worker     }
103*0ed15c77SAndroid Build Coastguard Worker 
put(String key, Object value)104*0ed15c77SAndroid Build Coastguard Worker     public void put(String key, Object value) {
105*0ed15c77SAndroid Build Coastguard Worker         if (map != null) {
106*0ed15c77SAndroid Build Coastguard Worker             map.put(key, value);
107*0ed15c77SAndroid Build Coastguard Worker         } else if ((tail + 2) > b.length) {
108*0ed15c77SAndroid Build Coastguard Worker             _expandMap(key, value);
109*0ed15c77SAndroid Build Coastguard Worker         } else {
110*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = key;
111*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = value;
112*0ed15c77SAndroid Build Coastguard Worker         }
113*0ed15c77SAndroid Build Coastguard Worker     }
114*0ed15c77SAndroid Build Coastguard Worker 
finishList(int prevStart)115*0ed15c77SAndroid Build Coastguard Worker     public List<Object> finishList(int prevStart)
116*0ed15c77SAndroid Build Coastguard Worker     {
117*0ed15c77SAndroid Build Coastguard Worker         List<Object> l = list;
118*0ed15c77SAndroid Build Coastguard Worker         if (l == null) {
119*0ed15c77SAndroid Build Coastguard Worker             l = _buildList(true);
120*0ed15c77SAndroid Build Coastguard Worker         } else {
121*0ed15c77SAndroid Build Coastguard Worker             list = null;
122*0ed15c77SAndroid Build Coastguard Worker         }
123*0ed15c77SAndroid Build Coastguard Worker         start = prevStart;
124*0ed15c77SAndroid Build Coastguard Worker         return l;
125*0ed15c77SAndroid Build Coastguard Worker     }
126*0ed15c77SAndroid Build Coastguard Worker 
finishArray(int prevStart)127*0ed15c77SAndroid Build Coastguard Worker     public Object[] finishArray(int prevStart)
128*0ed15c77SAndroid Build Coastguard Worker     {
129*0ed15c77SAndroid Build Coastguard Worker         Object[] result;
130*0ed15c77SAndroid Build Coastguard Worker         if (list == null) {
131*0ed15c77SAndroid Build Coastguard Worker             result = Arrays.copyOfRange(b, start, tail);
132*0ed15c77SAndroid Build Coastguard Worker         } else {
133*0ed15c77SAndroid Build Coastguard Worker             result = list.toArray(new Object[tail - start]);
134*0ed15c77SAndroid Build Coastguard Worker             list = null;
135*0ed15c77SAndroid Build Coastguard Worker         }
136*0ed15c77SAndroid Build Coastguard Worker         start = prevStart;
137*0ed15c77SAndroid Build Coastguard Worker         return result;
138*0ed15c77SAndroid Build Coastguard Worker     }
139*0ed15c77SAndroid Build Coastguard Worker 
finishArray(int prevStart, Class<T> elemType)140*0ed15c77SAndroid Build Coastguard Worker     public <T> Object[] finishArray(int prevStart, Class<T> elemType)
141*0ed15c77SAndroid Build Coastguard Worker     {
142*0ed15c77SAndroid Build Coastguard Worker         final int size = tail-start;
143*0ed15c77SAndroid Build Coastguard Worker         @SuppressWarnings("unchecked")
144*0ed15c77SAndroid Build Coastguard Worker         T[] result = (T[]) Array.newInstance(elemType, size);
145*0ed15c77SAndroid Build Coastguard Worker 
146*0ed15c77SAndroid Build Coastguard Worker         if (list == null) {
147*0ed15c77SAndroid Build Coastguard Worker             System.arraycopy(b, start, result, 0, size);
148*0ed15c77SAndroid Build Coastguard Worker         } else {
149*0ed15c77SAndroid Build Coastguard Worker             result = list.toArray(result);
150*0ed15c77SAndroid Build Coastguard Worker             list = null;
151*0ed15c77SAndroid Build Coastguard Worker         }
152*0ed15c77SAndroid Build Coastguard Worker         start = prevStart;
153*0ed15c77SAndroid Build Coastguard Worker         return result;
154*0ed15c77SAndroid Build Coastguard Worker     }
155*0ed15c77SAndroid Build Coastguard Worker 
finishMap(int prevStart)156*0ed15c77SAndroid Build Coastguard Worker     public Map<String,Object> finishMap(int prevStart)
157*0ed15c77SAndroid Build Coastguard Worker     {
158*0ed15c77SAndroid Build Coastguard Worker         Map<String,Object> m = map;
159*0ed15c77SAndroid Build Coastguard Worker 
160*0ed15c77SAndroid Build Coastguard Worker         if (m == null) {
161*0ed15c77SAndroid Build Coastguard Worker             m = _buildMap(true);
162*0ed15c77SAndroid Build Coastguard Worker         } else {
163*0ed15c77SAndroid Build Coastguard Worker             map = null;
164*0ed15c77SAndroid Build Coastguard Worker         }
165*0ed15c77SAndroid Build Coastguard Worker         start = prevStart;
166*0ed15c77SAndroid Build Coastguard Worker         return m;
167*0ed15c77SAndroid Build Coastguard Worker     }
168*0ed15c77SAndroid Build Coastguard Worker 
169*0ed15c77SAndroid Build Coastguard Worker     /*
170*0ed15c77SAndroid Build Coastguard Worker     /**********************************************************
171*0ed15c77SAndroid Build Coastguard Worker     /* Internal methods
172*0ed15c77SAndroid Build Coastguard Worker     /**********************************************************
173*0ed15c77SAndroid Build Coastguard Worker      */
174*0ed15c77SAndroid Build Coastguard Worker 
_expandList(Object value)175*0ed15c77SAndroid Build Coastguard Worker     private void _expandList(Object value) {
176*0ed15c77SAndroid Build Coastguard Worker         if (b.length < MAX_BUF) { // can still expand
177*0ed15c77SAndroid Build Coastguard Worker             b = Arrays.copyOf(b, b.length << 1);
178*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = value;
179*0ed15c77SAndroid Build Coastguard Worker         } else {
180*0ed15c77SAndroid Build Coastguard Worker             list = _buildList(false);
181*0ed15c77SAndroid Build Coastguard Worker             list.add(value);
182*0ed15c77SAndroid Build Coastguard Worker         }
183*0ed15c77SAndroid Build Coastguard Worker     }
184*0ed15c77SAndroid Build Coastguard Worker 
_buildList(boolean isComplete)185*0ed15c77SAndroid Build Coastguard Worker     private List<Object> _buildList(boolean isComplete)
186*0ed15c77SAndroid Build Coastguard Worker     {
187*0ed15c77SAndroid Build Coastguard Worker         int currLen = tail - start;
188*0ed15c77SAndroid Build Coastguard Worker         if (isComplete) {
189*0ed15c77SAndroid Build Coastguard Worker             if (currLen < 2) {
190*0ed15c77SAndroid Build Coastguard Worker                 currLen = 2;
191*0ed15c77SAndroid Build Coastguard Worker             }
192*0ed15c77SAndroid Build Coastguard Worker         } else {
193*0ed15c77SAndroid Build Coastguard Worker             if (currLen < 20) {
194*0ed15c77SAndroid Build Coastguard Worker                 currLen = 20;
195*0ed15c77SAndroid Build Coastguard Worker             } else if (currLen < MAX_BUF) {
196*0ed15c77SAndroid Build Coastguard Worker                 currLen += (currLen>>1);
197*0ed15c77SAndroid Build Coastguard Worker             } else {
198*0ed15c77SAndroid Build Coastguard Worker                 currLen += (currLen>>2);
199*0ed15c77SAndroid Build Coastguard Worker             }
200*0ed15c77SAndroid Build Coastguard Worker         }
201*0ed15c77SAndroid Build Coastguard Worker         List<Object> l = new ArrayList<Object>(currLen);
202*0ed15c77SAndroid Build Coastguard Worker         for (int i = start; i < tail; ++i) {
203*0ed15c77SAndroid Build Coastguard Worker             l.add(b[i]);
204*0ed15c77SAndroid Build Coastguard Worker         }
205*0ed15c77SAndroid Build Coastguard Worker         tail = start; // reset buffered entries
206*0ed15c77SAndroid Build Coastguard Worker         return l;
207*0ed15c77SAndroid Build Coastguard Worker     }
208*0ed15c77SAndroid Build Coastguard Worker 
_expandMap(String key, Object value)209*0ed15c77SAndroid Build Coastguard Worker     private void _expandMap(String key, Object value) {
210*0ed15c77SAndroid Build Coastguard Worker         if (b.length < MAX_BUF) { // can still expand
211*0ed15c77SAndroid Build Coastguard Worker             b = Arrays.copyOf(b, b.length << 1);
212*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = key;
213*0ed15c77SAndroid Build Coastguard Worker             b[tail++] = value;
214*0ed15c77SAndroid Build Coastguard Worker         } else {
215*0ed15c77SAndroid Build Coastguard Worker             map = _buildMap(false);
216*0ed15c77SAndroid Build Coastguard Worker             map.put(key, value);
217*0ed15c77SAndroid Build Coastguard Worker         }
218*0ed15c77SAndroid Build Coastguard Worker     }
219*0ed15c77SAndroid Build Coastguard Worker 
_buildMap(boolean isComplete)220*0ed15c77SAndroid Build Coastguard Worker     private Map<String,Object> _buildMap(boolean isComplete)
221*0ed15c77SAndroid Build Coastguard Worker     {
222*0ed15c77SAndroid Build Coastguard Worker         int size = (tail - start) >> 1;
223*0ed15c77SAndroid Build Coastguard Worker         if (isComplete) { // when complete, optimize to smallest size
224*0ed15c77SAndroid Build Coastguard Worker             if (size <= 3) { // 3 or fewer entries, hash table of 4
225*0ed15c77SAndroid Build Coastguard Worker                 size = 4;
226*0ed15c77SAndroid Build Coastguard Worker             } else if (size <= 40) {
227*0ed15c77SAndroid Build Coastguard Worker                 size += (size>>1);
228*0ed15c77SAndroid Build Coastguard Worker             } else {
229*0ed15c77SAndroid Build Coastguard Worker                 size += (size>>2) + (size>>4); // * 1.3125
230*0ed15c77SAndroid Build Coastguard Worker             }
231*0ed15c77SAndroid Build Coastguard Worker         } else {
232*0ed15c77SAndroid Build Coastguard Worker             if (size < 10) {
233*0ed15c77SAndroid Build Coastguard Worker                 size = 16;
234*0ed15c77SAndroid Build Coastguard Worker             } else if (size < MAX_BUF) {
235*0ed15c77SAndroid Build Coastguard Worker                 size += (size>>1);
236*0ed15c77SAndroid Build Coastguard Worker             } else {
237*0ed15c77SAndroid Build Coastguard Worker                 size += (size/3);
238*0ed15c77SAndroid Build Coastguard Worker             }
239*0ed15c77SAndroid Build Coastguard Worker         }
240*0ed15c77SAndroid Build Coastguard Worker         Map<String,Object> m = new LinkedHashMap<String,Object>(size, 0.8f);
241*0ed15c77SAndroid Build Coastguard Worker         for (int i = start; i < tail; i += 2) {
242*0ed15c77SAndroid Build Coastguard Worker             m.put((String) b[i], b[i+1]);
243*0ed15c77SAndroid Build Coastguard Worker         }
244*0ed15c77SAndroid Build Coastguard Worker         tail = start; // reset buffered entries
245*0ed15c77SAndroid Build Coastguard Worker         return m;
246*0ed15c77SAndroid Build Coastguard Worker     }
247*0ed15c77SAndroid Build Coastguard Worker }
248