001/*
002 * Copyright (c) 2011, 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.AbstractMap.SimpleEntry;
026import java.util.*;
027import java.util.Map.Entry;
028
029public class NodeMap<T> extends NodeIdAccessor {
030
031    private static final int MIN_REALLOC_SIZE = 16;
032
033    protected Object[] values;
034
035    public NodeMap(Graph graph) {
036        super(graph);
037        this.values = new Object[graph.nodeIdCount()];
038    }
039
040    public NodeMap(NodeMap<T> copyFrom) {
041        super(copyFrom.graph);
042        this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length);
043    }
044
045    @SuppressWarnings("unchecked")
046    public T get(Node node) {
047        assert check(node);
048        return (T) values[getNodeId(node)];
049    }
050
051    @SuppressWarnings("unchecked")
052    public T getAndGrow(Node node) {
053        checkAndGrow(node);
054        return (T) values[getNodeId(node)];
055    }
056
057    private void checkAndGrow(Node node) {
058        if (isNew(node)) {
059            this.values = Arrays.copyOf(values, Math.max(MIN_REALLOC_SIZE, graph.nodeIdCount() * 3 / 2));
060        }
061        assert check(node);
062    }
063
064    public boolean isEmpty() {
065        return !entries().iterator().hasNext();
066    }
067
068    public boolean containsKey(Object key) {
069        if (key instanceof Node) {
070            Node node = (Node) key;
071            if (node.graph() == graph()) {
072                return get(node) != null;
073            }
074        }
075        return false;
076    }
077
078    public boolean containsValue(Object value) {
079        for (Object o : values) {
080            if (o == value) {
081                return true;
082            }
083        }
084        return false;
085    }
086
087    public Graph graph() {
088        return graph;
089    }
090
091    public void set(Node node, T value) {
092        assert check(node);
093        values[getNodeId(node)] = value;
094    }
095
096    public void setAndGrow(Node node, T value) {
097        checkAndGrow(node);
098        values[getNodeId(node)] = value;
099    }
100
101    /**
102     * @param i
103     * @return Return the key for the entry at index {@code i}
104     */
105    protected Node getKey(int i) {
106        return graph.getNode(i);
107    }
108
109    public int size() {
110        return values.length;
111    }
112
113    public boolean isNew(Node node) {
114        return getNodeId(node) >= size();
115    }
116
117    private boolean check(Node node) {
118        assert node.graph() == graph : String.format("%s is not part of the graph", node);
119        assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
120        return true;
121    }
122
123    public void clear() {
124        Arrays.fill(values, null);
125    }
126
127    public Iterable<Entry<Node, T>> entries() {
128        return new Iterable<Entry<Node, T>>() {
129
130            @Override
131            public Iterator<Entry<Node, T>> iterator() {
132                return new Iterator<Entry<Node, T>>() {
133
134                    int i = 0;
135
136                    @Override
137                    public boolean hasNext() {
138                        forward();
139                        return i < NodeMap.this.values.length;
140                    }
141
142                    @SuppressWarnings("unchecked")
143                    @Override
144                    public Entry<Node, T> next() {
145                        final int pos = i;
146                        Node key = NodeMap.this.getKey(pos);
147                        T value = (T) NodeMap.this.values[pos];
148                        i++;
149                        forward();
150                        return new SimpleEntry<Node, T>(key, value) {
151
152                            private static final long serialVersionUID = 7813842391085737738L;
153
154                            @Override
155                            public T setValue(T v) {
156                                T oldv = super.setValue(v);
157                                NodeMap.this.values[pos] = v;
158                                return oldv;
159                            }
160                        };
161                    }
162
163                    @Override
164                    public void remove() {
165                        throw new UnsupportedOperationException();
166                    }
167
168                    private void forward() {
169                        while (i < NodeMap.this.values.length && (NodeMap.this.getKey(i) == null || NodeMap.this.values[i] == null)) {
170                            i++;
171                        }
172                    }
173                };
174            }
175        };
176    }
177
178    @Override
179    public String toString() {
180        Iterator<Entry<Node, T>> i = entries().iterator();
181        if (!i.hasNext()) {
182            return "{}";
183        }
184
185        StringBuilder sb = new StringBuilder();
186        sb.append('{');
187        while (true) {
188            Entry<Node, T> e = i.next();
189            Node key = e.getKey();
190            T value = e.getValue();
191            sb.append(key);
192            sb.append('=');
193            sb.append(value);
194            if (!i.hasNext()) {
195                return sb.append('}').toString();
196            }
197            sb.append(',').append(' ');
198        }
199    }
200}