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
33 @Override
34 public void recycle(CodecOutputList object) {
35
36 }
37 };
38
39 private static final FastThreadLocal<CodecOutputLists> CODEC_OUTPUT_LISTS_POOL =
40 new FastThreadLocal<CodecOutputLists>() {
41 @Override
42 protected CodecOutputLists initialValue() throws Exception {
43
44 return new CodecOutputLists(16);
45 }
46 };
47
48 private interface CodecOutputListRecycler {
49 void recycle(CodecOutputList codecOutputList);
50 }
51
52 private static final class CodecOutputLists implements CodecOutputListRecycler {
53 private final CodecOutputList[] elements;
54 private final int mask;
55
56 private int currentIdx;
57 private int count;
58
59 CodecOutputLists(int numElements) {
60 elements = new CodecOutputList[MathUtil.safeFindNextPositivePowerOfTwo(numElements)];
61 for (int i = 0; i < elements.length; ++i) {
62
63 elements[i] = new CodecOutputList(this, 16);
64 }
65 count = elements.length;
66 currentIdx = elements.length;
67 mask = elements.length - 1;
68 }
69
70 public CodecOutputList getOrCreate() {
71 if (count == 0) {
72
73
74 return new CodecOutputList(NOOP_RECYCLER, 4);
75 }
76 --count;
77
78 int idx = (currentIdx - 1) & mask;
79 CodecOutputList list = elements[idx];
80 currentIdx = idx;
81 return list;
82 }
83
84 @Override
85 public void recycle(CodecOutputList codecOutputList) {
86 int idx = currentIdx;
87 elements[idx] = codecOutputList;
88 currentIdx = (idx + 1) & mask;
89 ++count;
90 assert count <= elements.length;
91 }
92 }
93
94 static CodecOutputList newInstance() {
95 return CODEC_OUTPUT_LISTS_POOL.get().getOrCreate();
96 }
97
98 private final CodecOutputListRecycler recycler;
99 private int size;
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 - 1) {
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 size = 0;
179 }
180
181
182
183
184 boolean insertSinceRecycled() {
185 return insertSinceRecycled;
186 }
187
188
189
190
191 void recycle() {
192 for (int i = 0 ; i < size; i ++) {
193 array[i] = null;
194 }
195 size = 0;
196 insertSinceRecycled = false;
197
198 recycler.recycle(this);
199 }
200
201
202
203
204 Object getUnsafe(int index) {
205 return array[index];
206 }
207
208 private void checkIndex(int index) {
209 if (index >= size) {
210 throw new IndexOutOfBoundsException();
211 }
212 }
213
214 private void insert(int index, Object element) {
215 array[index] = element;
216 insertSinceRecycled = true;
217 }
218
219 private void expandArray() {
220
221 int newCapacity = array.length << 1;
222
223 if (newCapacity < 0) {
224 throw new OutOfMemoryError();
225 }
226
227 Object[] newArray = new Object[newCapacity];
228 System.arraycopy(array, 0, newArray, 0, array.length);
229
230 array = newArray;
231 }
232 }