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 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) { 145 return v; 146 } 147 } 148 return defaultValue; 149 } 150 return super.computeValue(map, key, value, valueNotFound); 151 } 152 }; 153 } 154 return new SliceWithOpposite<K, V>(rewritePolicy, opposite, keyNormalizer); 155 } 156 } 157 158 public static class BasicRemovableSlice<K, V> extends BasicWritableSlice<K, V> implements RemovableSlice<K, V> { 159 protected BasicRemovableSlice(RewritePolicy rewritePolicy) { 160 super(rewritePolicy); 161 } 162 163 protected BasicRemovableSlice(RewritePolicy rewritePolicy, boolean isCollective) { 164 super(rewritePolicy, isCollective); 165 } 166 } 167 168 public static class SliceWithOpposite<K, V> extends BasicRemovableSlice<K, V> { 169 private final WritableSlice<? super V, ? super K> opposite; 170 171 172 private final KeyNormalizer<K> keyNormalizer; 173 174 public SliceWithOpposite(String debugName, RewritePolicy rewritePolicy) { 175 this(debugName, rewritePolicy, KeyNormalizer.DO_NOTHING); 176 } 177 178 public SliceWithOpposite(String debugName, RewritePolicy rewritePolicy, KeyNormalizer<K> keyNormalizer) { 179 this(rewritePolicy, null, keyNormalizer); 180 } 181 182 public SliceWithOpposite(RewritePolicy rewritePolicy, WritableSlice<? super V, ? super K> opposite, KeyNormalizer<K> keyNormalizer) { 183 super(rewritePolicy); 184 this.opposite = opposite; 185 this.keyNormalizer = keyNormalizer; 186 } 187 188 @Override 189 public void afterPut(MutableSlicedMap map, K key, V value) { 190 if (opposite != null) { 191 map.put(opposite, value, key); 192 } 193 } 194 @Override 195 public SlicedMapKey<K, V> makeKey(K key) { 196 if (keyNormalizer == null) { 197 return super.makeKey(key); 198 } 199 return super.makeKey(keyNormalizer.normalize(key)); 200 } 201 202 } 203 204 public static class SetSlice<K> extends BasicRemovableSlice<K, Boolean> { 205 206 protected SetSlice(RewritePolicy rewritePolicy) { 207 this(rewritePolicy, false); 208 } 209 210 protected SetSlice(RewritePolicy rewritePolicy, boolean collective) { 211 super(rewritePolicy, collective); 212 } 213 214 @Override 215 public Boolean computeValue(SlicedMap map, K key, Boolean value, boolean valueNotFound) { 216 Boolean result = super.computeValue(map, key, value, valueNotFound); 217 return result != null ? result : false; 218 } 219 } 220 221 }