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