1 /*
   2  * Copyright (c) 2011, 2019, 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 
  24 
  25 package org.graalvm.compiler.graph;
  26 
  27 import java.util.AbstractList;
  28 import java.util.Arrays;
  29 import java.util.Collection;
  30 import java.util.Iterator;
  31 import java.util.List;
  32 import java.util.RandomAccess;
  33 
  34 import org.graalvm.compiler.graph.iterators.NodeIterable;
  35 
  36 public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess {
  37 
  38     protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
  39 
  40     protected final Node self;
  41     protected Node[] nodes;
  42     private int size;
  43     protected final int initialSize;
  44 
  45     protected NodeList(Node self) {
  46         this.self = self;
  47         this.nodes = EMPTY_NODE_ARRAY;
  48         this.initialSize = 0;
  49     }
  50 
  51     protected NodeList(Node self, int initialSize) {
  52         this.self = self;
  53         this.size = initialSize;
  54         this.initialSize = initialSize;
  55         this.nodes = new Node[initialSize];
  56     }
  57 
  58     protected NodeList(Node self, T[] elements) {
  59         this.self = self;
  60         if (elements == null || elements.length == 0) {
  61             this.size = 0;
  62             this.nodes = EMPTY_NODE_ARRAY;
  63             this.initialSize = 0;
  64         } else {
  65             this.size = elements.length;
  66             this.initialSize = elements.length;
  67             this.nodes = new Node[elements.length];
  68             for (int i = 0; i < elements.length; i++) {
  69                 this.nodes[i] = elements[i];
  70                 assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i];
  71             }
  72         }
  73     }
  74 
  75     protected NodeList(Node self, List<? extends T> elements) {
  76         this.self = self;
  77         if (elements == null || elements.isEmpty()) {
  78             this.size = 0;
  79             this.nodes = EMPTY_NODE_ARRAY;
  80             this.initialSize = 0;
  81         } else {
  82             this.size = elements.size();
  83             this.initialSize = elements.size();
  84             this.nodes = new Node[elements.size()];
  85             for (int i = 0; i < elements.size(); i++) {
  86                 this.nodes[i] = elements.get(i);
  87                 assert this.nodes[i] == null || !this.nodes[i].isDeleted();
  88             }
  89         }
  90     }
  91 
  92     protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
  93         this.self = self;
  94         if (elements == null || elements.isEmpty()) {
  95             this.size = 0;
  96             this.nodes = EMPTY_NODE_ARRAY;
  97             this.initialSize = 0;
  98         } else {
  99             this.size = elements.size();
 100             this.initialSize = elements.size();
 101             this.nodes = new Node[elements.size()];
 102             int i = 0;
 103             for (NodeInterface n : elements) {
 104                 this.nodes[i] = n.asNode();
 105                 assert this.nodes[i] == null || !this.nodes[i].isDeleted();
 106                 i++;
 107             }
 108         }
 109     }
 110 
 111     /**
 112      * Removes null values from the list.
 113      */
 114     public void trim() {
 115         int newSize = 0;
 116         for (int i = 0; i < nodes.length; ++i) {
 117             if (nodes[i] != null) {
 118                 nodes[newSize] = nodes[i];
 119                 newSize++;
 120             }
 121         }
 122         size = newSize;
 123     }
 124 
 125     public boolean isList() {
 126         return true;
 127     }
 128 
 129     protected abstract void update(T oldNode, T newNode);
 130 
 131     public abstract Edges.Type getEdgesType();
 132 
 133     @Override
 134     public final int size() {
 135         return size;
 136     }
 137 
 138     @Override
 139     public final boolean isEmpty() {
 140         return size == 0;
 141     }
 142 
 143     @Override
 144     public boolean isNotEmpty() {
 145         return size > 0;
 146     }
 147 
 148     @Override
 149     public int count() {
 150         return size;
 151     }
 152 
 153     protected final void incModCount() {
 154         modCount++;
 155     }
 156 
 157     @SuppressWarnings("unchecked")
 158     @Override
 159     public boolean add(Node node) {
 160         assert node == null || !node.isDeleted() : node;
 161         self.incModCount();
 162         incModCount();
 163         int length = nodes.length;
 164         if (length == 0) {
 165             nodes = new Node[2];
 166         } else if (size == length) {
 167             Node[] newNodes = new Node[nodes.length * 2 + 1];
 168             System.arraycopy(nodes, 0, newNodes, 0, length);
 169             nodes = newNodes;
 170         }
 171         nodes[size++] = node;
 172         update(null, (T) node);
 173         return true;
 174     }
 175 
 176     @Override
 177     @SuppressWarnings("unchecked")
 178     public T get(int index) {
 179         assert assertInRange(index);
 180         return (T) nodes[index];
 181     }
 182 
 183     private boolean assertInRange(int index) {
 184         assert index >= 0 && index < size() : index + " < " + size();
 185         return true;
 186     }
 187 
 188     public T last() {
 189         return get(size() - 1);
 190     }
 191 
 192     @Override
 193     @SuppressWarnings("unchecked")
 194     public T set(int index, Node node) {
 195         incModCount();
 196         T oldValue = (T) nodes[index];
 197         assert assertInRange(index);
 198         update((T) nodes[index], (T) node);
 199         nodes[index] = node;
 200         return oldValue;
 201     }
 202 
 203     public void initialize(int index, Node node) {
 204         incModCount();
 205         assert index < size();
 206         nodes[index] = node;
 207     }
 208 
 209     void copy(NodeList<? extends Node> other) {
 210         self.incModCount();
 211         incModCount();
 212         Node[] newNodes = new Node[other.size];
 213         System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length);
 214         nodes = newNodes;
 215         size = other.size;
 216     }
 217 
 218     @Override
 219     public boolean equals(Object other) {
 220         if (other == this) {
 221             return true;
 222         }
 223         if (other instanceof List<?>) {
 224             List<?> otherList = (List<?>) other;
 225             if (size != otherList.size()) {
 226                 return false;
 227             }
 228             for (int i = 0; i < size; i++) {
 229                 if (nodes[i] != otherList.get(i)) {
 230                     return false;
 231                 }
 232             }
 233             return true;
 234         }
 235         return false;
 236     }
 237 
 238     @SuppressWarnings("unchecked")
 239     @Override
 240     public void clear() {
 241         self.incModCount();
 242         incModCount();
 243         for (int i = 0; i < size; i++) {
 244             update((T) nodes[i], null);
 245         }
 246         clearWithoutUpdate();
 247     }
 248 
 249     void clearWithoutUpdate() {
 250         nodes = EMPTY_NODE_ARRAY;
 251         size = 0;
 252     }
 253 
 254     @Override
 255     @SuppressWarnings("unchecked")
 256     public boolean remove(Object node) {
 257         self.incModCount();
 258         int i = 0;
 259         incModCount();
 260         while (i < size && nodes[i] != node) {
 261             i++;
 262         }
 263         if (i < size) {
 264             T oldValue = (T) nodes[i];
 265             i++;
 266             while (i < size) {
 267                 nodes[i - 1] = nodes[i];
 268                 i++;
 269             }
 270             nodes[--size] = null;
 271             update(oldValue, null);
 272             return true;
 273         } else {
 274             return false;
 275         }
 276     }
 277 
 278     @Override
 279     @SuppressWarnings("unchecked")
 280     public T remove(int index) {
 281         self.incModCount();
 282         T oldValue = (T) nodes[index];
 283         int i = index + 1;
 284         incModCount();
 285         while (i < size) {
 286             nodes[i - 1] = nodes[i];
 287             i++;
 288         }
 289         nodes[--size] = null;
 290         update(oldValue, null);
 291         return oldValue;
 292     }
 293 
 294     boolean replaceFirst(Node node, Node other) {
 295         for (int i = 0; i < size; i++) {
 296             if (nodes[i] == node) {
 297                 nodes[i] = other;
 298                 return true;
 299             }
 300         }
 301         return false;
 302     }
 303 
 304     @Override
 305     public Iterator<T> iterator() {
 306         return new NodeListIterator<>(this, 0);
 307     }
 308 
 309     @Override
 310     public boolean contains(T other) {
 311         for (int i = 0; i < size; i++) {
 312             if (nodes[i] == other) {
 313                 return true;
 314             }
 315         }
 316         return false;
 317     }
 318 
 319     @SuppressWarnings("unchecked")
 320     @Override
 321     public List<T> snapshot() {
 322         return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size));
 323     }
 324 
 325     @Override
 326     public void snapshotTo(Collection<? super T> to) {
 327         for (int i = 0; i < size; i++) {
 328             to.add(get(i));
 329         }
 330     }
 331 
 332     @SuppressWarnings("unchecked")
 333     public void setAll(NodeList<T> values) {
 334         self.incModCount();
 335         incModCount();
 336         for (int i = 0; i < size(); i++) {
 337             update((T) nodes[i], null);
 338         }
 339         nodes = Arrays.copyOf(values.nodes, values.size());
 340         size = values.size();
 341 
 342         for (int i = 0; i < size(); i++) {
 343             update(null, (T) nodes[i]);
 344         }
 345     }
 346 
 347     @Override
 348     @SuppressWarnings("unchecked")
 349     public <A> A[] toArray(A[] a) {
 350         if (a.length >= size) {
 351             System.arraycopy(nodes, 0, a, 0, size);
 352             return a;
 353         }
 354         return (A[]) Arrays.copyOf(nodes, size, a.getClass());
 355     }
 356 
 357     @Override
 358     public Object[] toArray() {
 359         return Arrays.copyOf(nodes, size);
 360     }
 361 
 362     protected void replace(T node, T other) {
 363         incModCount();
 364         for (int i = 0; i < size(); i++) {
 365             if (nodes[i] == node) {
 366                 nodes[i] = other;
 367                 update(node, other);
 368             }
 369         }
 370     }
 371 
 372     @Override
 373     public int indexOf(Object node) {
 374         for (int i = 0; i < size; i++) {
 375             if (nodes[i] == node) {
 376                 return i;
 377             }
 378         }
 379         return -1;
 380     }
 381 
 382     @Override
 383     public boolean contains(Object o) {
 384         return indexOf(o) != -1;
 385     }
 386 
 387     @Override
 388     public boolean containsAll(Collection<?> c) {
 389         throw new UnsupportedOperationException("not implemented");
 390     }
 391 
 392     @Override
 393     public boolean addAll(Collection<? extends T> c) {
 394         for (T e : c) {
 395             add(e);
 396         }
 397         return true;
 398     }
 399 
 400     public boolean addAll(T[] c) {
 401         for (T e : c) {
 402             add(e);
 403         }
 404         return true;
 405     }
 406 
 407     @Override
 408     public String toString() {
 409         StringBuilder sb = new StringBuilder();
 410         sb.append('[');
 411         for (int i = 0; i < size; i++) {
 412             if (i != 0) {
 413                 sb.append(", ");
 414             }
 415             sb.append(nodes[i]);
 416         }
 417         sb.append(']');
 418         return sb.toString();
 419     }
 420 
 421     @Override
 422     public T first() {
 423         if (size() > 0) {
 424             return get(0);
 425         }
 426         return null;
 427     }
 428 
 429     public SubList<T> subList(int startIndex) {
 430         assert assertInRange(startIndex);
 431         return new SubList<>(this, startIndex);
 432     }
 433 
 434     public static final class SubList<R extends Node> extends AbstractList<R> implements NodeIterable<R>, RandomAccess {
 435         private final NodeList<R> list;
 436         private final int offset;
 437 
 438         private SubList(NodeList<R> list, int offset) {
 439             this.list = list;
 440             this.offset = offset;
 441         }
 442 
 443         @Override
 444         public R get(int index) {
 445             assert index >= 0 : index;
 446             return list.get(offset + index);
 447         }
 448 
 449         @Override
 450         public int size() {
 451             return list.size() - offset;
 452         }
 453 
 454         public SubList<R> subList(int startIndex) {
 455             assert startIndex >= 0 && startIndex < size() : startIndex;
 456             return new SubList<>(this.list, startIndex + offset);
 457         }
 458 
 459         @Override
 460         public Iterator<R> iterator() {
 461             return new NodeListIterator<>(list, offset);
 462         }
 463     }
 464 
 465     private static final class NodeListIterator<R extends Node> implements Iterator<R> {
 466         private final NodeList<R> list;
 467         private final int expectedModCount;
 468         private int index;
 469 
 470         private NodeListIterator(NodeList<R> list, int startIndex) {
 471             this.list = list;
 472             this.expectedModCount = list.modCount;
 473             this.index = startIndex;
 474         }
 475 
 476         @Override
 477         public boolean hasNext() {
 478             assert expectedModCount == list.modCount;
 479             return index < list.size;
 480         }
 481 
 482         @SuppressWarnings("unchecked")
 483         @Override
 484         public R next() {
 485             assert expectedModCount == list.modCount;
 486             return (R) list.nodes[index++];
 487         }
 488 
 489         @Override
 490         public void remove() {
 491             throw new UnsupportedOperationException();
 492         }
 493     }
 494 }