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