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