1 /*
   2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.graph;
  24 
  25 import java.util.AbstractList;
  26 import java.util.Arrays;
  27 import java.util.Collection;
  28 import java.util.Iterator;
  29 import java.util.List;
  30 import java.util.RandomAccess;
  31 
  32 import org.graalvm.compiler.graph.iterators.NodeIterable;
  33 
  34 public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess {
  35 
  36     protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
  37 
  38     protected final Node self;
  39     protected Node[] nodes;
  40     private int size;
  41     protected final int initialSize;
  42 
  43     protected NodeList(Node self) {
  44         this.self = self;
  45         this.nodes = EMPTY_NODE_ARRAY;
  46         this.initialSize = 0;
  47     }
  48 
  49     protected NodeList(Node self, int initialSize) {
  50         this.self = self;
  51         this.size = initialSize;
  52         this.initialSize = initialSize;
  53         this.nodes = new Node[initialSize];
  54     }
  55 
  56     protected NodeList(Node self, T[] elements) {
  57         this.self = self;
  58         if (elements == null || elements.length == 0) {
  59             this.size = 0;
  60             this.nodes = EMPTY_NODE_ARRAY;
  61             this.initialSize = 0;
  62         } else {
  63             this.size = elements.length;
  64             this.initialSize = elements.length;
  65             this.nodes = new Node[elements.length];
  66             for (int i = 0; i < elements.length; i++) {
  67                 this.nodes[i] = elements[i];
  68                 assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i];
  69             }
  70         }
  71     }
  72 
  73     protected NodeList(Node self, List<? extends T> elements) {
  74         this.self = self;
  75         if (elements == null || elements.isEmpty()) {
  76             this.size = 0;
  77             this.nodes = EMPTY_NODE_ARRAY;
  78             this.initialSize = 0;
  79         } else {
  80             this.size = elements.size();
  81             this.initialSize = elements.size();
  82             this.nodes = new Node[elements.size()];
  83             for (int i = 0; i < elements.size(); i++) {
  84                 this.nodes[i] = elements.get(i);
  85                 assert this.nodes[i] == null || !this.nodes[i].isDeleted();
  86             }
  87         }
  88     }
  89 
  90     protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
  91         this.self = self;
  92         if (elements == null || elements.isEmpty()) {
  93             this.size = 0;
  94             this.nodes = EMPTY_NODE_ARRAY;
  95             this.initialSize = 0;
  96         } else {
  97             this.size = elements.size();
  98             this.initialSize = elements.size();
  99             this.nodes = new Node[elements.size()];
 100             int i = 0;
 101             for (NodeInterface n : elements) {
 102                 this.nodes[i] = n.asNode();
 103                 assert this.nodes[i] == null || !this.nodes[i].isDeleted();
 104                 i++;
 105             }
 106         }
 107     }
 108 
 109     public boolean isList() {
 110         return true;
 111     }
 112 
 113     protected abstract void update(T oldNode, T newNode);
 114 
 115     public abstract Edges.Type getEdgesType();
 116 
 117     @Override
 118     public final int size() {
 119         return size;
 120     }
 121 
 122     @Override
 123     public final boolean isEmpty() {
 124         return size == 0;
 125     }
 126 
 127     @Override
 128     public boolean isNotEmpty() {
 129         return size > 0;
 130     }
 131 
 132     @Override
 133     public int count() {
 134         return size;
 135     }
 136 
 137     protected final void incModCount() {
 138         modCount++;
 139     }
 140 
 141     @SuppressWarnings("unchecked")
 142     @Override
 143     public boolean add(Node node) {
 144         assert node == null || !node.isDeleted();
 145         self.incModCount();
 146         incModCount();
 147         int length = nodes.length;
 148         if (length == 0) {
 149             nodes = new Node[2];
 150         } else if (size == length) {
 151             Node[] newNodes = new Node[nodes.length * 2 + 1];
 152             System.arraycopy(nodes, 0, newNodes, 0, length);
 153             nodes = newNodes;
 154         }
 155         nodes[size++] = node;
 156         update(null, (T) node);
 157         return true;
 158     }
 159 
 160     @Override
 161     @SuppressWarnings("unchecked")
 162     public T get(int index) {
 163         assert assertInRange(index);
 164         return (T) nodes[index];
 165     }
 166 
 167     private boolean assertInRange(int index) {
 168         assert index >= 0 && index < size() : index + " < " + size();
 169         return true;
 170     }
 171 
 172     public T last() {
 173         return get(size() - 1);
 174     }
 175 
 176     @Override
 177     @SuppressWarnings("unchecked")
 178     public T set(int index, Node node) {
 179         incModCount();
 180         T oldValue = (T) nodes[index];
 181         assert assertInRange(index);
 182         update((T) nodes[index], (T) node);
 183         nodes[index] = node;
 184         return oldValue;
 185     }
 186 
 187     public void initialize(int index, Node node) {
 188         incModCount();
 189         assert index < size();
 190         nodes[index] = node;
 191     }
 192 
 193     void copy(NodeList<? extends Node> other) {
 194         self.incModCount();
 195         incModCount();
 196         Node[] newNodes = new Node[other.size];
 197         System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length);
 198         nodes = newNodes;
 199         size = other.size;
 200     }
 201 
 202     public boolean equals(NodeList<T> other) {
 203         if (size != other.size) {
 204             return false;
 205         }
 206         for (int i = 0; i < size; i++) {
 207             if (nodes[i] != other.nodes[i]) {
 208                 return false;
 209             }
 210         }
 211         return true;
 212     }
 213 
 214     @SuppressWarnings("unchecked")
 215     @Override
 216     public void clear() {
 217         self.incModCount();
 218         incModCount();
 219         for (int i = 0; i < size; i++) {
 220             update((T) nodes[i], null);
 221         }
 222         clearWithoutUpdate();
 223     }
 224 
 225     void clearWithoutUpdate() {
 226         nodes = EMPTY_NODE_ARRAY;
 227         size = 0;
 228     }
 229 
 230     @Override
 231     @SuppressWarnings("unchecked")
 232     public boolean remove(Object node) {
 233         self.incModCount();
 234         int i = 0;
 235         incModCount();
 236         while (i < size && nodes[i] != node) {
 237             i++;
 238         }
 239         if (i < size) {
 240             T oldValue = (T) nodes[i];
 241             i++;
 242             while (i < size) {
 243                 nodes[i - 1] = nodes[i];
 244                 i++;
 245             }
 246             nodes[--size] = null;
 247             update(oldValue, null);
 248             return true;
 249         } else {
 250             return false;
 251         }
 252     }
 253 
 254     @Override
 255     @SuppressWarnings("unchecked")
 256     public T remove(int index) {
 257         self.incModCount();
 258         T oldValue = (T) nodes[index];
 259         int i = index + 1;
 260         incModCount();
 261         while (i < size) {
 262             nodes[i - 1] = nodes[i];
 263             i++;
 264         }
 265         nodes[--size] = null;
 266         update(oldValue, null);
 267         return oldValue;
 268     }
 269 
 270     boolean replaceFirst(Node node, Node other) {
 271         for (int i = 0; i < size; i++) {
 272             if (nodes[i] == node) {
 273                 nodes[i] = other;
 274                 return true;
 275             }
 276         }
 277         return false;
 278     }
 279 
 280     @Override
 281     public Iterator<T> iterator() {
 282         return new NodeListIterator<>(this, 0);
 283     }
 284 
 285     @Override
 286     public boolean contains(T other) {
 287         for (int i = 0; i < size; i++) {
 288             if (nodes[i] == other) {
 289                 return true;
 290             }
 291         }
 292         return false;
 293     }
 294 
 295     @SuppressWarnings("unchecked")
 296     @Override
 297     public List<T> snapshot() {
 298         return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size));
 299     }
 300 
 301     @Override
 302     public void snapshotTo(Collection<? super T> to) {
 303         for (int i = 0; i < size; i++) {
 304             to.add(get(i));
 305         }
 306     }
 307 
 308     @SuppressWarnings("unchecked")
 309     public void setAll(NodeList<T> values) {
 310         self.incModCount();
 311         incModCount();
 312         for (int i = 0; i < size(); i++) {
 313             update((T) nodes[i], null);
 314         }
 315         nodes = Arrays.copyOf(values.nodes, values.size());
 316         size = values.size();
 317 
 318         for (int i = 0; i < size(); i++) {
 319             update(null, (T) nodes[i]);
 320         }
 321     }
 322 
 323     @Override
 324     @SuppressWarnings("unchecked")
 325     public <A> A[] toArray(A[] a) {
 326         if (a.length >= size) {
 327             System.arraycopy(nodes, 0, a, 0, size);
 328             return a;
 329         }
 330         return (A[]) Arrays.copyOf(nodes, size, a.getClass());
 331     }
 332 
 333     @Override
 334     public Object[] toArray() {
 335         return Arrays.copyOf(nodes, size);
 336     }
 337 
 338     protected void replace(T node, T other) {
 339         incModCount();
 340         for (int i = 0; i < size(); i++) {
 341             if (nodes[i] == node) {
 342                 nodes[i] = other;
 343                 update(node, other);
 344             }
 345         }
 346     }
 347 
 348     @Override
 349     public int indexOf(Object node) {
 350         for (int i = 0; i < size; i++) {
 351             if (nodes[i] == node) {
 352                 return i;
 353             }
 354         }
 355         return -1;
 356     }
 357 
 358     @Override
 359     public boolean contains(Object o) {
 360         return indexOf(o) != -1;
 361     }
 362 
 363     @Override
 364     public boolean containsAll(Collection<?> c) {
 365         throw new UnsupportedOperationException("not implemented");
 366     }
 367 
 368     @Override
 369     public boolean addAll(Collection<? extends T> c) {
 370         for (T e : c) {
 371             add(e);
 372         }
 373         return true;
 374     }
 375 
 376     public boolean addAll(T[] c) {
 377         for (T e : c) {
 378             add(e);
 379         }
 380         return true;
 381     }
 382 
 383     @Override
 384     public String toString() {
 385         StringBuilder sb = new StringBuilder();
 386         sb.append('[');
 387         for (int i = 0; i < size; i++) {
 388             if (i != 0) {
 389                 sb.append(", ");
 390             }
 391             sb.append(nodes[i]);
 392         }
 393         sb.append(']');
 394         return sb.toString();
 395     }
 396 
 397     @Override
 398     public T first() {
 399         if (size() > 0) {
 400             return get(0);
 401         }
 402         return null;
 403     }
 404 
 405     public SubList<T> subList(int startIndex) {
 406         assert assertInRange(startIndex);
 407         return new SubList<>(this, startIndex);
 408     }
 409 
 410     public static final class SubList<R extends Node> extends AbstractList<R> implements NodeIterable<R>, RandomAccess {
 411         private final NodeList<R> list;
 412         private final int offset;
 413 
 414         private SubList(NodeList<R> list, int offset) {
 415             this.list = list;
 416             this.offset = offset;
 417         }
 418 
 419         @Override
 420         public R get(int index) {
 421             assert index >= 0 : index;
 422             return list.get(offset + index);
 423         }
 424 
 425         @Override
 426         public int size() {
 427             return list.size() - offset;
 428         }
 429 
 430         public SubList<R> subList(int startIndex) {
 431             assert startIndex >= 0 && startIndex < size() : startIndex;
 432             return new SubList<>(this.list, startIndex + offset);
 433         }
 434 
 435         @Override
 436         public Iterator<R> iterator() {
 437             return new NodeListIterator<>(list, offset);
 438         }
 439     }
 440 
 441     private static final class NodeListIterator<R extends Node> implements Iterator<R> {
 442         private final NodeList<R> list;
 443         private final int expectedModCount;
 444         private int index;
 445 
 446         private NodeListIterator(NodeList<R> list, int startIndex) {
 447             this.list = list;
 448             this.expectedModCount = list.modCount;
 449             this.index = startIndex;
 450         }
 451 
 452         @Override
 453         public boolean hasNext() {
 454             assert expectedModCount == list.modCount;
 455             return index < list.size;
 456         }
 457 
 458         @SuppressWarnings("unchecked")
 459         @Override
 460         public R next() {
 461             assert expectedModCount == list.modCount;
 462             return (R) list.nodes[index++];
 463         }
 464 
 465         @Override
 466         public void remove() {
 467             throw new UnsupportedOperationException();
 468         }
 469     }
 470 }