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 import org.jetbrains.kotlin.psi.JetElement;
022 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
023
024 import java.util.Arrays;
025 import java.util.List;
026
027 public class Slices {
028 private static final Logger LOG = Logger.getInstance(Slices.class);
029
030 public static final RewritePolicy ONLY_REWRITE_TO_EQUAL = new RewritePolicy() {
031 @Override
032 public <K> boolean rewriteProcessingNeeded(K key) {
033 return true;
034 }
035
036 @Override
037 public <K, V> boolean processRewrite(WritableSlice<K, V> slice, K key, V oldValue, V newValue) {
038 if (!((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue)))) {
039 // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception
040 LOG.error("Rewrite at slice " + slice +
041 " key: " + key +
042 " old value: " + oldValue + '@' + System.identityHashCode(oldValue) +
043 " new value: " + newValue + '@' + System.identityHashCode(newValue) +
044 (key instanceof JetElement ? "\n" + PsiUtilPackage.getElementTextWithContext((JetElement) key) : ""));
045 }
046 return true;
047 }
048 };
049
050 private Slices() {
051 }
052
053 public static <K, V> SliceBuilder<K, V> sliceBuilder() {
054 return new SliceBuilder<K, V>(ONLY_REWRITE_TO_EQUAL);
055 }
056
057 public static <K, V> WritableSlice<K, V> createSimpleSlice() {
058 return new BasicWritableSlice<K, V>(ONLY_REWRITE_TO_EQUAL);
059 }
060
061 public static <K, V> WritableSlice<K, V> createCollectiveSlice() {
062 return new BasicWritableSlice<K, V>(ONLY_REWRITE_TO_EQUAL, true);
063 }
064
065 public static <K> WritableSlice<K, Boolean> createSimpleSetSlice() {
066 return new SetSlice<K>(RewritePolicy.DO_NOTHING);
067 }
068
069 public static <K> WritableSlice<K, Boolean> createCollectiveSetSlice() {
070 return new SetSlice<K>(RewritePolicy.DO_NOTHING, true);
071 }
072
073 public static class SliceBuilder<K, V> {
074 private List<ReadOnlySlice<K, V>> furtherLookupSlices;
075 private final RewritePolicy rewritePolicy;
076 private String debugName;
077
078 private SliceBuilder(RewritePolicy rewritePolicy) {
079 this.rewritePolicy = rewritePolicy;
080 }
081
082 public SliceBuilder<K, V> setFurtherLookupSlices(ReadOnlySlice<K, V>... furtherLookupSlices) {
083 this.furtherLookupSlices = Arrays.asList(furtherLookupSlices);
084 return this;
085 }
086
087 public SliceBuilder<K, V> setDebugName(@NotNull String debugName) {
088 this.debugName = debugName;
089 return this;
090 }
091
092 public WritableSlice<K, V> build() {
093 BasicWritableSlice<K, V> result = doBuild();
094 if (debugName != null) {
095 result.setDebugName(debugName);
096 }
097 return result;
098 }
099
100 private BasicWritableSlice<K, V> doBuild() {
101 if (furtherLookupSlices != null) {
102 return new BasicWritableSlice<K, V>(rewritePolicy) {
103 @Override
104 public V computeValue(SlicedMap map, K key, V value, boolean valueNotFound) {
105 if (valueNotFound) {
106 for (ReadOnlySlice<K, V> slice : furtherLookupSlices) {
107 V v = map.get(slice, key);
108 if (v != null) {
109 return v;
110 }
111 }
112 return null;
113 }
114 return super.computeValue(map, key, value, false);
115 }
116 };
117 }
118 return new BasicWritableSlice<K, V>(rewritePolicy);
119 }
120 }
121
122 public static class SetSlice<K> extends BasicWritableSlice<K, Boolean> {
123
124 protected SetSlice(RewritePolicy rewritePolicy) {
125 this(rewritePolicy, false);
126 }
127
128 protected SetSlice(RewritePolicy rewritePolicy, boolean collective) {
129 super(rewritePolicy, collective);
130 }
131
132 @Override
133 public Boolean computeValue(SlicedMap map, K key, Boolean value, boolean valueNotFound) {
134 Boolean result = super.computeValue(map, key, value, valueNotFound);
135 return result != null ? result : false;
136 }
137 }
138
139 }