/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

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