PageRenderTime 373ms CodeModel.GetById 120ms app.highlight 117ms RepoModel.GetById 131ms app.codeStats 0ms

/src/org/ooc/frontend/model/NodeList.java

http://github.com/nddrylliog/ooc
Java | 395 lines | 325 code | 66 blank | 4 comment | 64 complexity | 842c54362c6d6eb7b8f1fa3722b2fe23 MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4import java.util.Collection;
  5import java.util.Iterator;
  6import java.util.List;
  7
  8import org.ooc.frontend.Visitor;
  9import org.ooc.frontend.model.tokens.Token;
 10
 11public class NodeList<T extends Node> extends Node implements Iterable<T>, Collection<T> {
 12	
 13	public static interface AddListener<T extends Node> {
 14		
 15		public void onAdd(NodeList<T> list, T element);
 16		
 17	}
 18	
 19	private T[] nodes;
 20	private int size;
 21	private AddListener<T> addListener = null;
 22	
 23	public NodeList() {
 24		this(Token.defaultToken);
 25	}
 26	
 27	public NodeList(Token startToken) {
 28		this(5, startToken);
 29	}
 30	
 31	public void addAddListener(AddListener<T> addListener) {
 32		this.addListener = addListener;
 33	}
 34	
 35	@SuppressWarnings("unchecked")
 36	public NodeList(int initialCapacity, Token startToken) {
 37		super(startToken);
 38		nodes = (T[]) new Node[initialCapacity];
 39		size = 0;
 40	}
 41
 42	@SuppressWarnings("unchecked")
 43	private void realloc() {
 44		Object[] oldNodes = nodes;
 45		nodes = (T[]) new Node[(size * 3) / 2 + 1];
 46		System.arraycopy(oldNodes, 0, nodes, 0, size);
 47	}
 48	
 49	@SuppressWarnings("unchecked")
 50	private void ensureCapacity(int minCapacity) {
 51		if(minCapacity > nodes.length) {
 52			Object[] oldNodes = nodes;
 53			nodes = (T[]) new Node[minCapacity];
 54			System.arraycopy(oldNodes, 0, nodes, 0, size);
 55		}
 56	}
 57	
 58	public boolean add(T element) {
 59		if(size >= nodes.length) realloc();
 60		nodes[size++] = element;
 61		if(addListener != null) addListener.onAdd(this, element);
 62		return true;
 63	}
 64
 65	public void add(int index, T element) {
 66		if(size + 1 >= nodes.length) realloc();
 67		System.arraycopy(nodes, index, nodes, index + 1, size - index);
 68		nodes[index] = element;
 69		size++;
 70		if(addListener != null) addListener.onAdd(this, element);
 71	}
 72	
 73	public boolean remove(T element) {
 74		for (int index = 0; index < size; index++) {
 75			if(element.equals(nodes[index])) {
 76				fastRemove(index);
 77				return true;
 78			}
 79		}
 80		return false;
 81	}
 82	
 83	public T removeAt(int index) {
 84		T o = nodes[index];
 85        fastRemove(index);
 86        return o;
 87	}
 88
 89	private void fastRemove(int index) {
 90		int numMoved = size - index - 1;
 91		if (numMoved > 0) {
 92            System.arraycopy(nodes, index+1, nodes, index, numMoved);
 93        }
 94		size--;
 95	}
 96	
 97	public void clear() {
 98		size = 0;
 99	}
100	
101	public boolean contains(T element) {
102		for (int index = 0; index < size; index++) {
103			if(element.equals(nodes[index])) {
104				return true;
105			}
106		}
107		return false;
108	}
109	
110	public int indexOf(T lostSheep) {
111		for (int index = 0; index < size; index++) {
112			if(lostSheep.equals(nodes[index])) {
113				return index;
114			}
115		}
116		return -1;
117	}
118
119	
120	public int size() {
121		return size;
122	}
123	
124	public boolean isEmpty() {
125		return size == 0;
126	}
127	
128	public T get(int i) {
129		if(i >= size) throw new ArrayIndexOutOfBoundsException(i);
130		return nodes[i];
131	}
132	
133	public void set(int i, T element) {
134		if(i > size) throw new ArrayIndexOutOfBoundsException(i);
135		nodes[i] = element;
136	}
137	
138	public void setAll(NodeList<T> list) {
139		nodes = list.nodes;
140	}
141	
142	public T getFirst() {
143		if(size == 0) throw new ArrayIndexOutOfBoundsException(0);
144		return nodes[0];
145	}
146	
147	public T getLast() {
148		if(size == 0) throw new ArrayIndexOutOfBoundsException(0);
149		return nodes[size - 1];
150	}
151	
152	public T getBeforeLast() {
153		if(size <= 1) throw new ArrayIndexOutOfBoundsException(size - 1);
154		return nodes[size - 2];
155	}
156
157	public Iterator<T> iterator() {		
158		return new Iterator<T>() {
159
160			NodeList<T> list = NodeList.this;
161			int index = 0;
162			
163			public boolean hasNext() {
164				return index < list.size();
165			}
166
167			public T next() {
168				if(index >= list.size()) throw new ArrayIndexOutOfBoundsException(index);
169				return list.getNodes()[index++];
170			}
171
172			public void remove() {
173				NodeList.this.removeAt(index);
174			}
175			
176		};
177	}
178
179	public void accept(Visitor visitor) throws IOException {
180		visitor.visit(this);
181	}
182
183	public void acceptChildren(Visitor visitor) throws IOException {
184		for(int i = 0; i < size; i++) {
185			if(nodes[i] != null) nodes[i].accept(visitor);
186		}
187	}
188
189	public boolean hasChildren() {
190		return size > 0;
191	}
192
193	@Override
194	@SuppressWarnings("unchecked")
195	public boolean replace(Node oldie, Node kiddo) {
196		int index = indexOf((T) oldie);
197		if(index == -1) {
198			String oldieClassName = oldie == null ? "null" : oldie.getClass().getSimpleName();
199			String kiddoClassName = kiddo == null ? "null" : kiddo.getClass().getSimpleName();
200			System.out.println("Trying to replace "+oldie+" with "+kiddo+" in a list with \n"+toString());
201			throw new ArrayIndexOutOfBoundsException("Trying to replace a "
202					+oldieClassName+" with a "+kiddoClassName+
203					" in a "+this.getClass().getSimpleName()+", but couldn't find node to replace in NodeList.");
204		}
205		nodes[index] = (T) kiddo;
206		return true;
207	}
208
209	public void addAll(NodeList<T> list) {
210		int newSize = size + list.size;
211		ensureCapacity(newSize);
212		System.arraycopy(list.nodes, 0, nodes, size, list.size);
213		size = newSize;
214	}
215	
216	public void addAll(List<T> list) {
217		int newSize = size + list.size();
218		ensureCapacity(newSize);
219		int index = size;
220		for(T o : list) {
221			nodes[index++] = o;
222		}
223	}
224
225	public T[] getNodes() {
226		return nodes;
227	}
228	
229	@Override
230	public String toString() {
231		return toString(false);
232	}
233	
234	public String toString(boolean stackLike) {
235		return toString(stackLike, 0);
236	}
237	
238	public String toString(boolean stackLike, int offset) {
239		if(size == 0) return "[]";
240		StringBuilder sB = new StringBuilder();
241		for(int i = 0; i < offset; i++) sB.append("  ");
242		if(stackLike) {
243			sB.append('\n');
244		} else {
245			sB.append('[');
246		}
247		int index = 0;
248		while(index < size) {
249			T node = nodes[index++];
250			if(node instanceof NodeList<?>) {
251				sB.append(((NodeList<?>) node).toString(false, stackLike ? offset + index : offset));
252			} else {
253				if(stackLike) {
254					for(int i = 0; i < index; i++) sB.append("  ");
255				} else if(index > 1) {
256					sB.append(", ");
257				}
258				if(node == null) sB.append("null");
259				else sB.append(node.toString());
260			}
261			if(stackLike && index < size) sB.append("\n");
262		}
263		if(!stackLike) sB.append(']');
264		return sB.toString();
265	}
266
267	public void push(T node) {
268		if(size + 1 > nodes.length) realloc();
269		nodes[size++] = node;
270	}
271	
272	/**
273	 * Checked pop: ensures it's this node we are removing
274	 * @param coverDecl
275	 */
276	public void pop(T node) {
277		if(peek() == node)
278			pop();
279		else
280			throw new Error("Unmatched node in checked pop: "+node+". peek is "+peek());
281	}
282
283	public void pop() {
284		if(size <= 0) throw new ArrayIndexOutOfBoundsException(0);
285		size--;
286	}
287
288	public T peek() {
289		return nodes[size - 1];
290	}
291	
292	public T peek(int i) {
293		return nodes[size - i];
294	}
295	
296	public int find(Class<?> clazz) {
297		return find(clazz, size - 1);
298	}
299		
300	public int find(Class<?> clazz, int offset) {
301		int i = offset;
302		while(i >= 0) {
303			T node = nodes[i];
304			if(clazz.isInstance(node)) {
305				return i;
306			}
307			i--;
308		}
309		
310		return -1;
311	}
312
313	public Module getModule() {
314		return (Module) nodes[0];
315	}
316	
317	public void addBefore(T beforeWhat, T kiddo) {
318		int index = indexOf(beforeWhat);
319		if(index == -1) {
320			throw new Error("Trying to add "+kiddo+" before "+beforeWhat+", but it can't be found in the list.");
321		}
322		add(index, kiddo);
323	}
324
325	public void addAfter(T afterWhat, T kiddo) {
326		int index = indexOf(afterWhat);
327		if(index == -1) {
328			throw new Error("Trying to add "+kiddo+" after "+afterWhat+", but it can't be found in the list.");
329		}
330		add(index + 1, kiddo);
331	}
332
333	public boolean addAll(Collection<? extends T> c) {
334		for(T t : c) {
335			add(t);
336		}
337		return true;
338	}
339
340	public boolean contains(Object o) {
341		return contains(o);
342	}
343
344	public boolean containsAll(Collection<?> c) {
345		boolean result = true;
346		for(T t : this) {
347			if(!c.contains(t)) {
348				result = false;
349				break;
350			}
351		}
352		return result;
353	}
354
355	@SuppressWarnings("unchecked")
356	public boolean remove(Object o) {
357		return remove((T) o);
358	}
359
360	public boolean removeAll(Collection<?> c) {
361		boolean removed = false;
362		for(T t : this) {
363			if(c.contains(t)) {
364				removed = true;
365				remove(t);
366			}
367		}
368		return removed;
369	}
370
371	public boolean retainAll(Collection<?> c) {
372		boolean removed = false;
373		for(T t : this) {
374			if(!c.contains(t)) {
375				removed = true;
376				remove(t);
377			}
378		}
379		return removed;
380	}
381
382	public Object[] toArray() {
383		Object[] array = new Object[size];
384		System.arraycopy(nodes, 0, array, 0, size);
385		return array;
386	}
387
388	@SuppressWarnings("unchecked")
389	public <T> T[] toArray(T[] arg) {
390		T[] array = (T[]) new Object[size];
391		System.arraycopy(nodes, 0, array, 0, size);
392		return array;
393	}
394	
395}