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 017 package org.jetbrains.jet.util.slicedmap; 018 019 import com.intellij.openapi.diagnostic.Logger; 020 import org.jetbrains.annotations.NotNull; 021 022 import java.util.Arrays; 023 import java.util.List; 024 025 public class Slices { 026 private static final Logger LOG = Logger.getInstance(Slices.class); 027 028 public static final RewritePolicy ONLY_REWRITE_TO_EQUAL = new RewritePolicy() { 029 @Override 030 public <K> boolean rewriteProcessingNeeded(K key) { 031 return true; 032 } 033 034 @Override 035 public <K, V> boolean processRewrite(WritableSlice<K, V> slice, K key, V oldValue, V newValue) { 036 if (!((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue)))) { 037 // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception 038 LOG.error("Rewrite at slice " + slice + 039 " key: " + key + 040 " old value: " + oldValue + '@' + System.identityHashCode(oldValue) + 041 " new value: " + newValue + '@' + System.identityHashCode(newValue)); 042 } 043 return true; 044 } 045 }; 046 047 private Slices() { 048 } 049 050 public interface KeyNormalizer<K> { 051 KeyNormalizer DO_NOTHING = new KeyNormalizer<Object>() { 052 @Override 053 public Object normalize(Object key) { 054 return key; 055 } 056 }; 057 058 K normalize(K key); 059 } 060 061 public static <K, V> SliceBuilder<K, V> sliceBuilder() { 062 return new SliceBuilder<K, V>(ONLY_REWRITE_TO_EQUAL); 063 } 064 065 public static <K, V> WritableSlice<K, V> createSimpleSlice() { 066 return new BasicWritableSlice<K, V>(ONLY_REWRITE_TO_EQUAL); 067 } 068 069 public static <K, V> WritableSlice<K, V> createCollectiveSlice() { 070 return new BasicWritableSlice<K, V>(ONLY_REWRITE_TO_EQUAL, true); 071 } 072 073 public static <K> WritableSlice<K, Boolean> createSimpleSetSlice() { 074 return createRemovableSetSlice(); 075 } 076 077 public static <K> WritableSlice<K, Boolean> createCollectiveSetSlice() { 078 return new SetSlice<K>(RewritePolicy.DO_NOTHING, true); 079 } 080 081 public static <K> RemovableSlice<K, Boolean> createRemovableSetSlice() { 082 return new SetSlice<K>(RewritePolicy.DO_NOTHING, false); 083 } 084 085 public static class SliceBuilder<K, V> { 086 private V defaultValue = null; 087 private List<ReadOnlySlice<K, V>> furtherLookupSlices = null; 088 private WritableSlice<? super V, ? super K> opposite = null; 089 private KeyNormalizer<K> keyNormalizer = null; 090 091 private final RewritePolicy rewritePolicy; 092 093 private String debugName; 094 095 private SliceBuilder(RewritePolicy rewritePolicy) { 096 this.rewritePolicy = rewritePolicy; 097 } 098 099 public SliceBuilder<K, V> setDefaultValue(V defaultValue) { 100 this.defaultValue = defaultValue; 101 return this; 102 } 103 104 public SliceBuilder<K, V> setFurtherLookupSlices(ReadOnlySlice<K, V>... furtherLookupSlices) { 105 this.furtherLookupSlices = Arrays.asList(furtherLookupSlices); 106 return this; 107 } 108 109 public SliceBuilder<K, V> setOpposite(WritableSlice<? super V, ? super K> opposite) { 110 this.opposite = opposite; 111 return this; 112 } 113 114 public SliceBuilder<K, V> setDebugName(@NotNull String debugName) { 115 this.debugName = debugName; 116 return this; 117 } 118 119 public SliceBuilder<K, V> setKeyNormalizer(KeyNormalizer<K> keyNormalizer) { 120 this.keyNormalizer = keyNormalizer; 121 return this; 122 } 123 124 public RemovableSlice<K, V> build() { 125 SliceWithOpposite<K, V> result = doBuild(); 126 if (debugName != null) { 127 result.setDebugName(debugName); 128 } 129 return result; 130 } 131 132 private SliceWithOpposite<K, V> doBuild() { 133 if (defaultValue != null) { 134 return new SliceWithOpposite<K, V>(rewritePolicy, opposite, keyNormalizer) { 135 @Override 136 public V computeValue(SlicedMap map, K key, V value, boolean valueNotFound) { 137 if (valueNotFound) return defaultValue; 138 return super.computeValue(map, key, value, false); 139 } 140 }; 141 } 142 if (furtherLookupSlices != null) { 143 return new SliceWithOpposite<K, V>(rewritePolicy, opposite, keyNormalizer) { 144 @Override 145 public V computeValue(SlicedMap map, K key, V value, boolean valueNotFound) { 146 if (valueNotFound) { 147 for (ReadOnlySlice<K, V> slice : furtherLookupSlices) { 148 V v = map.get(slice, key); 149 if (v != null) { 150 return v; 151 } 152 } 153 return defaultValue; 154 } 155 return super.computeValue(map, key, value, false); 156 } 157 }; 158 } 159 return new SliceWithOpposite<K, V>(rewritePolicy, opposite, keyNormalizer); 160 } 161 } 162 163 public static class BasicRemovableSlice<K, V> extends BasicWritableSlice<K, V> implements RemovableSlice<K, V> { 164 protected BasicRemovableSlice(RewritePolicy rewritePolicy) { 165 super(rewritePolicy); 166 } 167 168 protected BasicRemovableSlice(RewritePolicy rewritePolicy, boolean isCollective) { 169 super(rewritePolicy, isCollective); 170 } 171 } 172 173 public static class SliceWithOpposite<K, V> extends BasicRemovableSlice<K, V> { 174 private final WritableSlice<? super V, ? super K> opposite; 175 private final KeyNormalizer<K> keyNormalizer; 176 177 public SliceWithOpposite(RewritePolicy rewritePolicy, WritableSlice<? super V, ? super K> opposite, KeyNormalizer<K> keyNormalizer) { 178 super(rewritePolicy); 179 this.opposite = opposite; 180 this.keyNormalizer = keyNormalizer; 181 } 182 183 @Override 184 public void afterPut(MutableSlicedMap map, K key, V value) { 185 if (opposite != null) { 186 map.put(opposite, value, key); 187 } 188 } 189 @Override 190 public SlicedMapKey<K, V> makeKey(K key) { 191 if (keyNormalizer == null) { 192 return super.makeKey(key); 193 } 194 return super.makeKey(keyNormalizer.normalize(key)); 195 } 196 197 } 198 199 public static class SetSlice<K> extends BasicRemovableSlice<K, Boolean> { 200 201 protected SetSlice(RewritePolicy rewritePolicy) { 202 this(rewritePolicy, false); 203 } 204 205 protected SetSlice(RewritePolicy rewritePolicy, boolean collective) { 206 super(rewritePolicy, collective); 207 } 208 209 @Override 210 public Boolean computeValue(SlicedMap map, K key, Boolean value, boolean valueNotFound) { 211 Boolean result = super.computeValue(map, key, value, valueNotFound); 212 return result != null ? result : false; 213 } 214 } 215 216 }