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