001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.util.slicedmap; 018 019import com.google.common.collect.ImmutableMap; 020import com.google.common.collect.Maps; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.TestOnly; 023import org.jetbrains.jet.utils.Printer; 024 025import java.util.Collection; 026import java.util.Iterator; 027import java.util.Map; 028 029public class TrackingSlicedMap implements MutableSlicedMap { 030 031 private final MutableSlicedMap delegate; 032 private final Map<ReadOnlySlice<?, ?>, SliceWithStackTrace<?, ?>> sliceTranslationMap = Maps.newHashMap(); 033 034 public TrackingSlicedMap(@NotNull MutableSlicedMap delegate) { 035 this.delegate = delegate; 036 } 037 038 private <K, V> SliceWithStackTrace<K, V> wrapSlice(ReadOnlySlice<K, V> slice) { 039 SliceWithStackTrace<?, ?> translated = sliceTranslationMap.get(slice); 040 if (translated == null) { 041 translated = new SliceWithStackTrace<K, V>(slice); 042 sliceTranslationMap.put(slice, translated); 043 } 044 //noinspection unchecked 045 return (SliceWithStackTrace) translated; 046 } 047 048 @Override 049 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) { 050 return delegate.get(wrapSlice(slice), key).value; 051 } 052 053 @Override 054 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) { 055 return delegate.getKeys(wrapSlice(slice)); 056 } 057 058 @NotNull 059 @Override 060 public Iterator<Map.Entry<SlicedMapKey<?, ?>, ?>> iterator() { 061 Map<SlicedMapKey<?, ?>, Object> map = Maps.newHashMap(); 062 for (Map.Entry<SlicedMapKey<?, ?>, ?> entry : delegate) { 063 map.put(entry.getKey(), ((WithStackTrace<?>) entry.getValue()).value); 064 } 065 //noinspection unchecked 066 return (Iterator) map.entrySet().iterator(); 067 } 068 069 @Override 070 public <K, V> void put(WritableSlice<K, V> slice, K key, V value) { 071 delegate.put(wrapSlice(slice), key, new WithStackTrace<V>(value)); 072 } 073 074 @Override 075 public <K, V> V remove(RemovableSlice<K, V> slice, K key) { 076 return delegate.remove(wrapSlice(slice), key).value; 077 } 078 079 @Override 080 public void clear() { 081 delegate.clear(); 082 } 083 084 @Override 085 @NotNull 086 @TestOnly 087 public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) { 088 return delegate.getSliceContents(slice); 089 } 090 091 private static class WithStackTrace<V> { 092 private final V value; 093 private final StackTraceElement[] stackTrace; 094 095 private WithStackTrace(V value) { 096 this.value = value; 097 this.stackTrace = Thread.currentThread().getStackTrace(); 098 } 099 100 private Appendable printStackTrace(Appendable appendable) { 101 Printer s = new Printer(appendable); 102 s.println(value); 103 s.println("Written at "); 104 StackTraceElement[] trace = stackTrace; 105 for (StackTraceElement aTrace : trace) { 106 s.println("\tat " + aTrace); 107 } 108 s.println("---------"); 109 return appendable; 110 } 111 112 @Override 113 public String toString() { 114 return printStackTrace(new StringBuilder()).toString(); 115 } 116 117 @Override 118 public boolean equals(Object o) { 119 if (this == o) return true; 120 if (o == null || getClass() != o.getClass()) return false; 121 122 WithStackTrace other = (WithStackTrace) o; 123 124 if (value != null ? !value.equals(other.value) : other.value != null) return false; 125 126 return true; 127 } 128 129 @Override 130 public int hashCode() { 131 return value != null ? value.hashCode() : 0; 132 } 133 } 134 135 public class SliceWithStackTrace<K, V> implements RemovableSlice<K, WithStackTrace<V>> { 136 137 private final ReadOnlySlice<K, V> delegate; 138 139 private SliceWithStackTrace(@NotNull ReadOnlySlice<K, V> delegate) { 140 this.delegate = delegate; 141 } 142 143 // Methods of ReadOnlySlice 144 145 @Override 146 public SlicedMapKey<K, WithStackTrace<V>> makeKey(K key) { 147 //noinspection unchecked 148 return (SlicedMapKey) delegate.makeKey(key); 149 } 150 151 @Override 152 public WithStackTrace<V> computeValue(SlicedMap map, K key, WithStackTrace<V> value, boolean valueNotFound) { 153 return new WithStackTrace<V>(delegate.computeValue(map, key, value == null ? null : value.value, valueNotFound)); 154 } 155 156 @Override 157 public ReadOnlySlice<K, WithStackTrace<V>> makeRawValueVersion() { 158 return wrapSlice(delegate.makeRawValueVersion()); 159 } 160 161 // Methods of WritableSlice 162 163 private WritableSlice<K, V> getWritableDelegate() { 164 return (WritableSlice<K, V>) delegate; 165 } 166 167 @Override 168 public boolean isCollective() { 169 return getWritableDelegate().isCollective(); 170 } 171 172 @Override 173 public RewritePolicy getRewritePolicy() { 174 return getWritableDelegate().getRewritePolicy(); 175 } 176 177 @Override 178 public void afterPut(MutableSlicedMap map, K key, WithStackTrace<V> value) { 179 getWritableDelegate().afterPut(map, key, value.value); 180 } 181 182 @Override 183 public boolean check(K key, WithStackTrace<V> value) { 184 return getWritableDelegate().check(key, value.value); 185 } 186 } 187}