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.KtElement; 022 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; 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 KtElement ? "\n" + PsiUtilsKt.getElementTextWithContext((KtElement) 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 }