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 }