1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec;
17
18 import io.netty.util.concurrent.FastThreadLocal;
19 import io.netty.util.internal.MathUtil;
20
21 import java.util.AbstractList;
22 import java.util.RandomAccess;
23
24 import static io.netty.util.internal.ObjectUtil.checkNotNull;
25
26
27
28
29 final class CodecOutputList extends AbstractList<Object> implements RandomAccess {
30
31 private static final CodecOutputListRecycler NOOP_RECYCLER = new CodecOutputListRecycler() {
32 @Override
33 public void recycle(CodecOutputList object) {
34
35 }
36 };
37
38 private static final FastThreadLocal<CodecOutputLists> CODEC_OUTPUT_LISTS_POOL =
39 new FastThreadLocal<CodecOutputLists>() {
40 @Override
41 protected CodecOutputLists initialValue() throws Exception {
42
43 return new CodecOutputLists(16);
44 }
45 };
46
47 private interface CodecOutputListRecycler {
48 void recycle(CodecOutputList codecOutputList);
49 }
50
51 private static final class CodecOutputLists implements CodecOutputListRecycler {
52 private final CodecOutputList[] elements;
53 private final int mask;
54
55 private int currentIdx;
56 private int count;
57
58 CodecOutputLists(int numElements) {
59 elements = new CodecOutputList[MathUtil.safeFindNextPositivePowerOfTwo(numElements)];
60 for (int i = 0; i < elements.length; ++i) {
61
62 elements[i] = new CodecOutputList(this, 16);
63 }
64 count = elements.length;
65 currentIdx = elements.length;
66 mask = elements.length - 1;
67 }
68
69 public CodecOutputList getOrCreate() {
70 if (count == 0) {
71
72
73 return new CodecOutputList(NOOP_RECYCLER, 4);
74 }
75 --count;
76
77 int idx = (currentIdx - 1) & mask;
78 CodecOutputList list = elements[idx];
79 currentIdx = idx;
80 return list;
81 }
82
83 @Override
84 public void recycle(CodecOutputList codecOutputList) {
85 int idx = currentIdx;
86 elements[idx] = codecOutputList;
87 currentIdx = (idx + 1) & mask;
88 ++count;
89 assert count <= elements.length;
90 }
91 }
92
93 static CodecOutputList newInstance() {
94 return CODEC_OUTPUT_LISTS_POOL.get().getOrCreate();
95 }
96
97 private final CodecOutputListRecycler recycler;
98 private int size;
99 private int maxSeenSize;
100 private Object[] array;
101 private boolean insertSinceRecycled;
102
103 private CodecOutputList(CodecOutputListRecycler recycler, int size) {
104 this.recycler = recycler;
105 array = new Object[size];
106 }
107
108 @Override
109 public Object get(int index) {
110 checkIndex(index);
111 return array[index];
112 }
113
114 @Override
115 public int size() {
116 return size;
117 }
118
119 @Override
120 public boolean add(Object element) {
121 checkNotNull(element, "element");
122 try {
123 insert(size, element);
124 } catch (IndexOutOfBoundsException ignore) {
125
126 expandArray();
127 insert(size, element);
128 }
129 ++ size;
130 return true;
131 }
132
133 @Override
134 public Object set(int index, Object element) {
135 checkNotNull(element, "element");
136 checkIndex(index);
137
138 Object old = array[index];
139 insert(index, element);
140 return old;
141 }
142
143 @Override
144 public void add(int index, Object element) {
145 checkNotNull(element, "element");
146 checkIndex(index);
147
148 if (size == array.length) {
149 expandArray();
150 }
151
152 if (index != size) {
153 System.arraycopy(array, index, array, index + 1, size - index);
154 }
155
156 insert(index, element);
157 ++ size;
158 }
159
160 @Override
161 public Object remove(int index) {
162 checkIndex(index);
163 Object old = array[index];
164
165 int len = size - index - 1;
166 if (len > 0) {
167 System.arraycopy(array, index + 1, array, index, len);
168 }
169 array[-- size] = null;
170
171 return old;
172 }
173
174 @Override
175 public void clear() {
176
177
178 maxSeenSize = Math.max(maxSeenSize, size);
179 size = 0;
180 }
181
182
183
184
185 boolean insertSinceRecycled() {
186 return insertSinceRecycled;
187 }
188
189
190
191
192 void recycle() {
193 int len = Math.max(maxSeenSize, size);
194 for (int i = 0; i < len; i ++) {
195 array[i] = null;
196 }
197 size = 0;
198 maxSeenSize = 0;
199 insertSinceRecycled = false;
200
201 recycler.recycle(this);
202 }
203
204
205
206
207 Object getUnsafe(int index) {
208 return array[index];
209 }
210
211 private void checkIndex(int index) {
212 if (index >= size) {
213 throw new IndexOutOfBoundsException("expected: index < ("
214 + size + "),but actual is (" + size + ")");
215 }
216 }
217
218 private void insert(int index, Object element) {
219 array[index] = element;
220 insertSinceRecycled = true;
221 }
222
223 private void expandArray() {
224
225 int newCapacity = array.length << 1;
226
227 if (newCapacity < 0) {
228 throw new OutOfMemoryError();
229 }
230
231 Object[] newArray = new Object[newCapacity];
232 System.arraycopy(array, 0, newArray, 0, array.length);
233
234 array = newArray;
235 }
236 }