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 com.google.common.collect.ImmutableMap;
020    import com.google.common.collect.Maps;
021    import com.google.common.collect.Multimap;
022    import com.google.common.collect.Multimaps;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.jet.util.CommonSuppliers;
025    
026    import java.util.Collection;
027    import java.util.HashMap;
028    import java.util.Iterator;
029    import java.util.Map;
030    
031    public class SlicedMapImpl implements MutableSlicedMap {
032    
033        public static SlicedMapImpl create() {
034            return new SlicedMapImpl(Maps.<SlicedMapKey<?, ?>, Object>newLinkedHashMap());
035        }
036    
037        public static SlicedMapImpl create(Map<SlicedMapKey<?, ?>, Object> map) {
038            return new SlicedMapImpl(map);
039        }
040    
041        public static SlicedMapImpl create(MapSupplier mapSupplier) {
042            return new SlicedMapImpl(mapSupplier.<SlicedMapKey<?, ?>, Object>get());
043        }
044        
045        private final Map<SlicedMapKey<?, ?>, Object> map;
046        private final Multimap<WritableSlice<?, ?>, Object> collectiveSliceKeys = Multimaps.newListMultimap(new HashMap<WritableSlice<?, ?>, Collection<Object>>(), CommonSuppliers.getArrayListSupplier());
047    
048        protected SlicedMapImpl(Map<SlicedMapKey<?, ?>, Object> map) {
049            this.map = map;
050        }
051    
052        @Override
053        public <K, V> void put(WritableSlice<K, V> slice, K key, V value) {
054            if (!slice.check(key, value)) {
055                return;
056            }
057    
058            SlicedMapKey<K, V> slicedMapKey = slice.makeKey(key);
059            RewritePolicy rewritePolicy = slice.getRewritePolicy();
060            if (rewritePolicy.rewriteProcessingNeeded(key)) {
061                if (map.containsKey(slicedMapKey)) {
062                    //noinspection unchecked
063                    if (!rewritePolicy.processRewrite(slice, key, (V) map.get(slicedMapKey), value)) {
064                        return;
065                    }
066                }
067            }
068    
069            if (slice.isCollective()) {
070                collectiveSliceKeys.put(slice, key);
071            }
072    
073            map.put(slicedMapKey, value);
074            slice.afterPut(this, key, value);
075        }
076    
077        @Override
078        public void clear() {
079            map.clear();
080        }
081    
082        @Override
083        public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
084            SlicedMapKey<K, V> slicedMapKey = slice.makeKey(key);
085            //noinspection unchecked
086            V value = (V) map.get(slicedMapKey);
087            return slice.computeValue(this, key, value, value == null && !map.containsKey(slicedMapKey));
088        }
089    
090        @Override
091        @SuppressWarnings("unchecked")
092        public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
093            assert slice.isCollective() : "Keys are not collected for slice " + slice;
094            return (Collection<K>) collectiveSliceKeys.get(slice);
095        }
096    
097        @Override
098        public <K, V> V remove(RemovableSlice<K, V> slice, K key) {
099            //noinspection unchecked
100            return (V) map.remove(slice.makeKey(key));
101        }
102    
103        @NotNull
104        @Override
105        public Iterator<Map.Entry<SlicedMapKey<?, ?>, ?>> iterator() {
106            //noinspection unchecked
107            return (Iterator) map.entrySet().iterator();
108        }
109    
110        @NotNull
111        @Override
112        public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
113            ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
114            for (Map.Entry<SlicedMapKey<?, ?>, ?> entry : map.entrySet()) {
115                if (entry.getKey().getSlice() == slice) {
116                    builder.put((K) entry.getKey().getKey(), (V) entry.getValue());
117                }
118            }
119            return builder.build();
120        }
121    }