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.google.common.collect.ArrayListMultimap; 020 import com.google.common.collect.ImmutableMap; 021 import com.google.common.collect.Multimap; 022 import com.intellij.openapi.util.Key; 023 import com.intellij.openapi.util.UserDataHolder; 024 import gnu.trove.THashMap; 025 import kotlin.jvm.functions.Function3; 026 import org.jetbrains.annotations.NotNull; 027 028 import java.util.Collection; 029 import java.util.Collections; 030 import java.util.Map; 031 032 public class SlicedMapImpl implements MutableSlicedMap { 033 034 public static SlicedMapImpl create() { 035 return new SlicedMapImpl(); 036 } 037 038 private final Map<Object, UserDataHolderImpl> map = new THashMap<Object, UserDataHolderImpl>(0); 039 private Multimap<WritableSlice<?, ?>, Object> collectiveSliceKeys = null; 040 041 @Override 042 public <K, V> void put(WritableSlice<K, V> slice, K key, V value) { 043 if (!slice.check(key, value)) { 044 return; 045 } 046 047 UserDataHolderImpl holder = map.get(key); 048 if (holder == null) { 049 holder = new UserDataHolderImpl(); 050 map.put(key, holder); 051 } 052 053 Key<V> sliceKey = slice.getKey(); 054 055 RewritePolicy rewritePolicy = slice.getRewritePolicy(); 056 if (rewritePolicy.rewriteProcessingNeeded(key)) { 057 V oldValue = holder.getUserData(sliceKey); 058 if (oldValue != null) { 059 //noinspection unchecked 060 if (!rewritePolicy.processRewrite(slice, key, oldValue, value)) { 061 return; 062 } 063 } 064 } 065 066 if (slice.isCollective()) { 067 if (collectiveSliceKeys == null) { 068 collectiveSliceKeys = ArrayListMultimap.create(); 069 } 070 071 collectiveSliceKeys.put(slice, key); 072 } 073 074 holder.putUserData(sliceKey, value); 075 slice.afterPut(this, key, value); 076 } 077 078 @Override 079 public void clear() { 080 map.clear(); 081 collectiveSliceKeys = null; 082 } 083 084 @Override 085 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) { 086 UserDataHolderImpl holder = map.get(key); 087 088 V value = holder == null ? null : holder.getUserData(slice.getKey()); 089 090 return slice.computeValue(this, key, value, value == null); 091 } 092 093 @Override 094 @SuppressWarnings("unchecked") 095 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) { 096 assert slice.isCollective() : "Keys are not collected for slice " + slice; 097 098 if (collectiveSliceKeys == null) return Collections.emptyList(); 099 return (Collection<K>) collectiveSliceKeys.get(slice); 100 } 101 102 @Override 103 public <K, V> V remove(RemovableSlice<K, V> slice, K key) { 104 UserDataHolderImpl holder = map.get(key); 105 106 if (holder == null) return null; 107 108 Key<V> sliceKey = slice.getKey(); 109 V value = holder.getUserData(sliceKey); 110 111 holder.putUserData(sliceKey, null); 112 113 if (holder.isUserDataEmpty()) { 114 map.remove(key); 115 } 116 117 return value; 118 } 119 120 @Override 121 public void forEach(@NotNull Function3<WritableSlice, Object, Object, Void> f) { 122 for (Map.Entry<Object, UserDataHolderImpl> entry : map.entrySet()) { 123 Object key = entry.getKey(); 124 UserDataHolderImpl holder = entry.getValue(); 125 126 if (holder == null) continue; 127 128 for (Key<?> sliceKey : holder.getKeys()) { 129 Object value = holder.getUserData(sliceKey); 130 131 f.invoke(((AbstractWritableSlice) sliceKey).getSlice(), key, value); 132 } 133 } 134 } 135 136 @NotNull 137 @Override 138 public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) { 139 ImmutableMap.Builder<K, V> builder = ImmutableMap.builder(); 140 141 for (Map.Entry<Object, UserDataHolderImpl> entry : map.entrySet()) { 142 143 UserDataHolder holder = entry.getValue(); 144 145 V value = holder.getUserData(slice.getKey()); 146 147 if (value != null) { 148 //noinspection unchecked 149 builder.put((K) entry.getKey(), value); 150 } 151 } 152 return builder.build(); 153 } 154 }