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 Object[] array;
100 private boolean insertSinceRecycled;
101
102 private CodecOutputList(CodecOutputListRecycler recycler, int size) {
103 this.recycler = recycler;
104 array = new Object[size];
105 }
106
107 @Override
108 public Object get(int index) {
109 checkIndex(index);
110 return array[index];
111 }
112
113 @Override
114 public int size() {
115 return size;
116 }
117
118 @Override
119 public boolean add(Object element) {
120 checkNotNull(element, "element");
121 try {
122 insert(size, element);
123 } catch (IndexOutOfBoundsException ignore) {
124
125 expandArray();
126 insert(size, element);
127 }
128 ++ size;
129 return true;
130 }
131
132 @Override
133 public Object set(int index, Object element) {
134 checkNotNull(element, "element");
135 checkIndex(index);
136
137 Object old = array[index];
138 insert(index, element);
139 return old;
140 }
141
142 @Override
143 public void add(int index, Object element) {
144 checkNotNull(element, "element");
145 checkIndex(index);
146
147 if (size == array.length) {
148 expandArray();
149 }
150
151 if (index != size) {
152 System.arraycopy(array, index, array, index + 1, size - index);
153 }
154
155 insert(index, element);
156 ++ size;
157 }
158
159 @Override
160 public Object remove(int index) {
161 checkIndex(index);
162 Object old = array[index];
163
164 int len = size - index - 1;
165 if (len > 0) {
166 System.arraycopy(array, index + 1, array, index, len);
167 }
168 array[-- size] = null;
169
170 return old;
171 }
172
173 @Override
174 public void clear() {
175
176
177 size = 0;
178 }
179
180
181
182
183 boolean insertSinceRecycled() {
184 return insertSinceRecycled;
185 }
186
187
188
189
190 void recycle() {
191 for (int i = 0 ; i < size; i ++) {
192 array[i] = null;
193 }
194 size = 0;
195 insertSinceRecycled = false;
196
197 recycler.recycle(this);
198 }
199
200
201
202
203 Object getUnsafe(int index) {
204 return array[index];
205 }
206
207 private void checkIndex(int index) {
208 if (index >= size) {
209 throw new IndexOutOfBoundsException("expected: index < ("
210 + size + "),but actual is (" + size + ")");
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 }