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