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