001/*
002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.graph;
024
025import java.util.*;
026
027import com.oracle.graal.graph.iterators.*;
028
029public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess {
030
031    protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
032
033    protected final Node self;
034    protected Node[] nodes;
035    private int size;
036    protected final int initialSize;
037
038    protected NodeList(Node self) {
039        this.self = self;
040        this.nodes = EMPTY_NODE_ARRAY;
041        this.initialSize = 0;
042    }
043
044    protected NodeList(Node self, int initialSize) {
045        this.self = self;
046        this.size = initialSize;
047        this.initialSize = initialSize;
048        this.nodes = new Node[initialSize];
049    }
050
051    protected NodeList(Node self, T[] elements) {
052        this.self = self;
053        if (elements == null || elements.length == 0) {
054            this.size = 0;
055            this.nodes = EMPTY_NODE_ARRAY;
056            this.initialSize = 0;
057        } else {
058            this.size = elements.length;
059            this.initialSize = elements.length;
060            this.nodes = new Node[elements.length];
061            for (int i = 0; i < elements.length; i++) {
062                this.nodes[i] = elements[i];
063                assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i];
064            }
065        }
066    }
067
068    protected NodeList(Node self, List<? extends T> elements) {
069        this.self = self;
070        if (elements == null || elements.isEmpty()) {
071            this.size = 0;
072            this.nodes = EMPTY_NODE_ARRAY;
073            this.initialSize = 0;
074        } else {
075            this.size = elements.size();
076            this.initialSize = elements.size();
077            this.nodes = new Node[elements.size()];
078            for (int i = 0; i < elements.size(); i++) {
079                this.nodes[i] = elements.get(i);
080                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
081            }
082        }
083    }
084
085    protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
086        this.self = self;
087        if (elements == null || elements.isEmpty()) {
088            this.size = 0;
089            this.nodes = EMPTY_NODE_ARRAY;
090            this.initialSize = 0;
091        } else {
092            this.size = elements.size();
093            this.initialSize = elements.size();
094            this.nodes = new Node[elements.size()];
095            int i = 0;
096            for (NodeInterface n : elements) {
097                this.nodes[i] = n.asNode();
098                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
099                i++;
100            }
101        }
102    }
103
104    public boolean isList() {
105        return true;
106    }
107
108    protected abstract void update(T oldNode, T newNode);
109
110    public abstract Edges.Type getEdgesType();
111
112    @Override
113    public final int size() {
114        return size;
115    }
116
117    @Override
118    public final boolean isEmpty() {
119        return size == 0;
120    }
121
122    @Override
123    public boolean isNotEmpty() {
124        return size > 0;
125    }
126
127    @Override
128    public int count() {
129        return size;
130    }
131
132    protected final void incModCount() {
133        modCount++;
134    }
135
136    @SuppressWarnings("unchecked")
137    @Override
138    public boolean add(Node node) {
139        assert node == null || !node.isDeleted();
140        self.incModCount();
141        incModCount();
142        int length = nodes.length;
143        if (length == 0) {
144            nodes = new Node[2];
145        } else if (size == length) {
146            Node[] newNodes = new Node[nodes.length * 2 + 1];
147            System.arraycopy(nodes, 0, newNodes, 0, length);
148            nodes = newNodes;
149        }
150        nodes[size++] = node;
151        update(null, (T) node);
152        return true;
153    }
154
155    @Override
156    @SuppressWarnings("unchecked")
157    public T get(int index) {
158        assert assertInRange(index);
159        return (T) nodes[index];
160    }
161
162    private boolean assertInRange(int index) {
163        assert index < size() : index + " < " + size();
164        return true;
165    }
166
167    public T last() {
168        return get(size() - 1);
169    }
170
171    @Override
172    @SuppressWarnings("unchecked")
173    public T set(int index, Node node) {
174        incModCount();
175        T oldValue = (T) nodes[index];
176        assert assertInRange(index);
177        update((T) nodes[index], (T) node);
178        nodes[index] = node;
179        return oldValue;
180    }
181
182    public void initialize(int index, Node node) {
183        incModCount();
184        assert index < size();
185        nodes[index] = node;
186    }
187
188    void copy(NodeList<? extends Node> other) {
189        self.incModCount();
190        incModCount();
191        Node[] newNodes = new Node[other.size];
192        System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length);
193        nodes = newNodes;
194        size = other.size;
195    }
196
197    public boolean equals(NodeList<T> other) {
198        if (size != other.size) {
199            return false;
200        }
201        for (int i = 0; i < size; i++) {
202            if (nodes[i] != other.nodes[i]) {
203                return false;
204            }
205        }
206        return true;
207    }
208
209    @SuppressWarnings("unchecked")
210    @Override
211    public void clear() {
212        self.incModCount();
213        incModCount();
214        for (int i = 0; i < size; i++) {
215            update((T) nodes[i], null);
216        }
217        nodes = EMPTY_NODE_ARRAY;
218        size = 0;
219    }
220
221    @Override
222    @SuppressWarnings("unchecked")
223    public boolean remove(Object node) {
224        self.incModCount();
225        int i = 0;
226        incModCount();
227        while (i < size && nodes[i] != node) {
228            i++;
229        }
230        if (i < size) {
231            T oldValue = (T) nodes[i];
232            i++;
233            while (i < size) {
234                nodes[i - 1] = nodes[i];
235                i++;
236            }
237            nodes[--size] = null;
238            update(oldValue, null);
239            return true;
240        } else {
241            return false;
242        }
243    }
244
245    @Override
246    @SuppressWarnings("unchecked")
247    public T remove(int index) {
248        self.incModCount();
249        T oldValue = (T) nodes[index];
250        int i = index + 1;
251        incModCount();
252        while (i < size) {
253            nodes[i - 1] = nodes[i];
254            i++;
255        }
256        nodes[--size] = null;
257        update(oldValue, null);
258        return oldValue;
259    }
260
261    boolean replaceFirst(Node node, Node other) {
262        for (int i = 0; i < size; i++) {
263            if (nodes[i] == node) {
264                nodes[i] = other;
265                return true;
266            }
267        }
268        return false;
269    }
270
271    @Override
272    public Iterator<T> iterator() {
273        return new Iterator<T>() {
274
275            private final int expectedModCount = NodeList.this.modCount;
276            private int index = 0;
277
278            @Override
279            public boolean hasNext() {
280                assert expectedModCount == NodeList.this.modCount;
281                return index < NodeList.this.size;
282            }
283
284            @SuppressWarnings("unchecked")
285            @Override
286            public T next() {
287                assert expectedModCount == NodeList.this.modCount;
288                return (T) NodeList.this.nodes[index++];
289            }
290
291            @Override
292            public void remove() {
293                throw new UnsupportedOperationException();
294            }
295        };
296    }
297
298    @Override
299    public boolean contains(T other) {
300        for (int i = 0; i < size; i++) {
301            if (nodes[i] == other) {
302                return true;
303            }
304        }
305        return false;
306    }
307
308    @SuppressWarnings("unchecked")
309    @Override
310    public List<T> snapshot() {
311        return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size));
312    }
313
314    @Override
315    public void snapshotTo(Collection<? super T> to) {
316        for (int i = 0; i < size; i++) {
317            to.add(get(i));
318        }
319    }
320
321    @SuppressWarnings("unchecked")
322    public void setAll(NodeList<T> values) {
323        self.incModCount();
324        incModCount();
325        for (int i = 0; i < size(); i++) {
326            update((T) nodes[i], null);
327        }
328        nodes = Arrays.copyOf(values.nodes, values.size());
329        size = values.size();
330
331        for (int i = 0; i < size(); i++) {
332            update(null, (T) nodes[i]);
333        }
334    }
335
336    @Override
337    @SuppressWarnings("unchecked")
338    public <A> A[] toArray(A[] a) {
339        if (a.length >= size) {
340            System.arraycopy(nodes, 0, a, 0, size);
341            return a;
342        }
343        return (A[]) Arrays.copyOf(nodes, size, a.getClass());
344    }
345
346    @Override
347    public Object[] toArray() {
348        return Arrays.copyOf(nodes, size);
349    }
350
351    protected void replace(T node, T other) {
352        incModCount();
353        for (int i = 0; i < size(); i++) {
354            if (nodes[i] == node) {
355                nodes[i] = other;
356                update(node, other);
357            }
358        }
359    }
360
361    @Override
362    public int indexOf(Object node) {
363        for (int i = 0; i < size; i++) {
364            if (nodes[i] == node) {
365                return i;
366            }
367        }
368        return -1;
369    }
370
371    @Override
372    public boolean contains(Object o) {
373        return indexOf(o) != -1;
374    }
375
376    @Override
377    public boolean containsAll(Collection<?> c) {
378        throw new UnsupportedOperationException("not implemented");
379    }
380
381    @Override
382    public boolean addAll(Collection<? extends T> c) {
383        for (T e : c) {
384            add(e);
385        }
386        return true;
387    }
388
389    public boolean addAll(T[] c) {
390        for (T e : c) {
391            add(e);
392        }
393        return true;
394    }
395
396    @Override
397    public String toString() {
398        StringBuilder sb = new StringBuilder();
399        sb.append('[');
400        for (int i = 0; i < size; i++) {
401            if (i != 0) {
402                sb.append(", ");
403            }
404            sb.append(nodes[i]);
405        }
406        sb.append(']');
407        return sb.toString();
408    }
409
410    @Override
411    public T first() {
412        if (size() > 0) {
413            return get(0);
414        }
415        return null;
416    }
417}