1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.util.byteaccess;
21
22 import java.util.NoSuchElementException;
23
24 /**
25 * A linked list that stores <code>ByteArray</code>s and maintains several useful invariants.
26 *
27 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
28 */
29 class ByteArrayList {
30
31 /**
32 * A {@link Node} which indicates the start and end of the list and does not
33 * hold a value. The value of <code>next</code> is the first item in the
34 * list. The value of of <code>previous</code> is the last item in the list.
35 */
36 private final Node header;
37
38 /**
39 * The first byte in the array list
40 */
41 private int firstByte;
42
43 /**
44 * The last byte in the array list
45 */
46 private int lastByte;
47
48 /**
49 *
50 * Creates a new instance of ByteArrayList.
51 *
52 */
53 protected ByteArrayList() {
54 header = new Node();
55 }
56
57 /**
58 *
59 * Returns the last byte in the array list
60 *
61 * @return
62 * The last byte in the array list
63 */
64 public int lastByte() {
65 return lastByte;
66 }
67
68 /**
69 *
70 * Returns the first byte in the array list
71 *
72 * @return
73 * The first byte in the array list
74 */
75 public int firstByte() {
76 return firstByte;
77 }
78
79 /**
80 *
81 * Check to see if this is empty
82 *
83 * @return
84 * True if empty, otherwise false
85 */
86 public boolean isEmpty() {
87 return header.next == header;
88 }
89
90 /**
91 * Returns the first node in the byte array
92 *
93 * @return
94 *
95 */
96 public Node getFirst() {
97 return header.getNextNode();
98 }
99
100 /**
101 * Returns the last {@link Node} in the list
102 *
103 * @return
104 * The last node in the list
105 */
106 public Node getLast() {
107 return header.getPreviousNode();
108 }
109
110 /**
111 * Adds the specified {@link ByteArray} to
112 * the beginning of the list
113 *
114 * @param ba
115 * The ByteArray to be added to the list
116 */
117 public void addFirst(ByteArray ba) {
118 addNode(new Node(ba), header.next);
119 firstByte -= ba.last();
120 }
121
122 /**
123 * Add the specified {@link ByteArray} to
124 * the end of the list
125 *
126 * @param ba
127 * The ByteArray to be added to the list
128 */
129 public void addLast(ByteArray ba) {
130 addNode(new Node(ba), header);
131 lastByte += ba.last();
132 }
133
134 /**
135 * Removes the first node from this list
136 *
137 * @return
138 * The node that was removed
139 */
140 public Node removeFirst() {
141 Node node = header.getNextNode();
142 firstByte += node.ba.last();
143 return removeNode(node);
144 }
145
146 /**
147 * Removes the last node in this list
148 *
149 * @return
150 * The node that was taken off of the list
151 */
152 public Node removeLast() {
153 Node node = header.getPreviousNode();
154 lastByte -= node.ba.last();
155 return removeNode(node);
156 }
157
158 //-----------------------------------------------------------------------
159
160 /**
161 * Inserts a new node into the list.
162 *
163 * @param nodeToInsert new node to insert
164 * @param insertBeforeNode node to insert before
165 */
166 protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
167 // Insert node.
168 nodeToInsert.next = insertBeforeNode;
169 nodeToInsert.previous = insertBeforeNode.previous;
170 insertBeforeNode.previous.next = nodeToInsert;
171 insertBeforeNode.previous = nodeToInsert;
172 }
173
174 /**
175 * Removes the specified node from the list.
176 *
177 * @param node the node to remove
178 */
179 protected Node removeNode(Node node) {
180 // Remove node.
181 node.previous.next = node.next;
182 node.next.previous = node.previous;
183 node.removed = true;
184 return node;
185 }
186
187 //-----------------------------------------------------------------------
188 /**
189 * A node within the linked list.
190 * <p>
191 * From Commons Collections 3.1, all access to the <code>value</code> property
192 * is via the methods on this class.
193 */
194 public class Node {
195
196 /** A pointer to the node before this node */
197 private Node previous;
198
199 /** A pointer to the node after this node */
200 private Node next;
201
202 /** The ByteArray contained within this node */
203 private ByteArray ba;
204
205 private boolean removed;
206
207 /**
208 * Constructs a new header node.
209 */
210 private Node() {
211 super();
212 previous = this;
213 next = this;
214 }
215
216 /**
217 * Constructs a new node with a value.
218 */
219 private Node(ByteArray ba) {
220 super();
221
222 if (ba == null) {
223 throw new IllegalArgumentException("ByteArray must not be null.");
224 }
225
226 this.ba = ba;
227 }
228
229 /**
230 * Gets the previous node.
231 *
232 * @return the previous node
233 */
234 public Node getPreviousNode() {
235 if (!hasPreviousNode()) {
236 throw new NoSuchElementException();
237 }
238 return previous;
239 }
240
241 /**
242 * Gets the next node.
243 *
244 * @return the next node
245 */
246 public Node getNextNode() {
247 if (!hasNextNode()) {
248 throw new NoSuchElementException();
249 }
250 return next;
251 }
252
253 public boolean hasPreviousNode() {
254 return previous != header;
255 }
256
257 public boolean hasNextNode() {
258 return next != header;
259 }
260
261 public ByteArray getByteArray() {
262 return ba;
263 }
264
265 public boolean isRemoved() {
266 return removed;
267 }
268 }
269
270 }