001/* 002 * Copyright (c) 2014, 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.compiler.common; 024 025import java.util.*; 026import java.util.function.*; 027 028/** 029 * A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of 030 * ensuring a deterministic execution order during a capturing compilation. 031 */ 032final class LinkedIdentityHashMap<K, V> implements Map<K, V> { 033 034 private final LinkedHashMap<Id<K>, V> map; 035 036 public LinkedIdentityHashMap() { 037 map = new LinkedHashMap<>(); 038 } 039 040 public LinkedIdentityHashMap(Map<K, V> m) { 041 map = new LinkedHashMap<>(m.size()); 042 putAll(m); 043 } 044 045 public LinkedIdentityHashMap(int expectedMaxSize) { 046 map = new LinkedHashMap<>(expectedMaxSize); 047 } 048 049 /** 050 * Wrapper for an object that gives uses the object's identity for the purpose of equality 051 * comparisons and computing a hash code. 052 */ 053 static final class Id<T> { 054 final T object; 055 056 public Id(T object) { 057 assert object != null; 058 this.object = object; 059 } 060 061 @SuppressWarnings("unchecked") 062 @Override 063 public boolean equals(Object obj) { 064 return obj instanceof Id && ((Id<T>) obj).object == object; 065 } 066 067 @Override 068 public int hashCode() { 069 return System.identityHashCode(object); 070 } 071 } 072 073 public int size() { 074 return map.size(); 075 } 076 077 public boolean isEmpty() { 078 return map.isEmpty(); 079 } 080 081 public boolean containsKey(Object key) { 082 return map.containsKey(id(key)); 083 } 084 085 @SuppressWarnings("unchecked") 086 private Id<K> id(Object key) { 087 if (key == null) { 088 return null; 089 } 090 return new Id<>((K) key); 091 } 092 093 public boolean containsValue(Object value) { 094 return map.containsValue(value); 095 } 096 097 public V get(Object key) { 098 return map.get(id(key)); 099 } 100 101 public V put(K key, V value) { 102 return map.put(id(key), value); 103 } 104 105 public V remove(Object key) { 106 return map.remove(id(key)); 107 } 108 109 @SuppressWarnings("unchecked") 110 public void putAll(Map<? extends K, ? extends V> m) { 111 if (m == null) { 112 throw new NullPointerException(); 113 } 114 if (m.getClass() == getClass()) { 115 LinkedIdentityHashMap<K, V> that = (LinkedIdentityHashMap<K, V>) m; 116 map.putAll(that.map); 117 118 } else { 119 for (K key : m.keySet()) { 120 map.put(id(key), m.get(key)); 121 } 122 } 123 } 124 125 public void clear() { 126 map.clear(); 127 } 128 129 final class KeySet extends AbstractSet<K> { 130 @Override 131 public int size() { 132 return map.size(); 133 } 134 135 @Override 136 public void clear() { 137 map.clear(); 138 } 139 140 @Override 141 public Iterator<K> iterator() { 142 return new Iterator<K>() { 143 final Iterator<Id<K>> i = map.keySet().iterator(); 144 145 public boolean hasNext() { 146 return i.hasNext(); 147 } 148 149 public K next() { 150 return i.next().object; 151 } 152 153 public void remove() { 154 i.remove(); 155 } 156 }; 157 } 158 159 @Override 160 public boolean contains(Object o) { 161 return containsKey(o); 162 } 163 164 @Override 165 public boolean remove(Object o) { 166 return LinkedIdentityHashMap.this.remove(o) != null; 167 } 168 169 public Spliterator<K> spliterator() { 170 return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT); 171 } 172 173 public void forEach(Consumer<? super K> action) { 174 throw new UnsupportedOperationException(); 175 } 176 } 177 178 public Set<K> keySet() { 179 return new KeySet(); 180 } 181 182 public Collection<V> values() { 183 return map.values(); 184 } 185 186 final class EntrySet extends AbstractSet<Map.Entry<K, V>> { 187 @Override 188 public int size() { 189 return map.size(); 190 } 191 192 @Override 193 public void clear() { 194 map.clear(); 195 } 196 197 @Override 198 public Iterator<Map.Entry<K, V>> iterator() { 199 return new Iterator<Map.Entry<K, V>>() { 200 final Iterator<Map.Entry<Id<K>, V>> i = map.entrySet().iterator(); 201 202 public boolean hasNext() { 203 return i.hasNext(); 204 } 205 206 public Map.Entry<K, V> next() { 207 Map.Entry<Id<K>, V> e = i.next(); 208 return new Map.Entry<K, V>() { 209 210 public K getKey() { 211 return e.getKey().object; 212 } 213 214 public V getValue() { 215 return e.getValue(); 216 } 217 218 public V setValue(V value) { 219 return e.setValue(value); 220 } 221 }; 222 } 223 224 public void remove() { 225 i.remove(); 226 } 227 }; 228 } 229 230 @Override 231 public boolean contains(Object o) { 232 throw new UnsupportedOperationException(); 233 } 234 235 @Override 236 public boolean remove(Object o) { 237 throw new UnsupportedOperationException(); 238 } 239 240 public Spliterator<Map.Entry<K, V>> spliterator() { 241 throw new UnsupportedOperationException(); 242 } 243 244 public void forEach(Consumer<? super Map.Entry<K, V>> action) { 245 throw new UnsupportedOperationException(); 246 } 247 } 248 249 public Set<Map.Entry<K, V>> entrySet() { 250 return new EntrySet(); 251 } 252}