View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.util.graph.manager;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.HashMap;
24  
25  /**
26   * Warning: this is a special map-like construct that suits only and should be used only in this package!
27   * It has the following properties:
28   * <ul>
29   *     <li>memorizes once calculated hashCode</li>
30   *     <li>once hashCode calculated, goes into "read only" mode (put method will fail)</li>
31   *     <li>otherwise all the rest is same as for {@link HashMap}</li>
32   * </ul>
33   *
34   * This class is not a generic map class; only those methods are "protected" that are in use in this very
35   * package.
36   *
37   * @param <K>
38   * @param <V>
39   */
40  public class MMap<K, V> {
41      private static final MMap<?, ?> EMPTY_MAP = new MMap<>(new HashMap<>(0)).done();
42  
43      /**
44       * Returns empty "done" (immutable) MMap.
45       */
46      @SuppressWarnings("unchecked")
47      public static <K, V> MMap<K, V> empty() {
48          return (MMap<K, V>) MMap.EMPTY_MAP;
49      }
50  
51      /**
52       * Returns empty "not done" (mutable) MMap.
53       */
54      public static <K, V> MMap<K, V> emptyNotDone() {
55          return new MMap<>(new HashMap<>());
56      }
57  
58      public static <K, V> MMap<K, V> copy(MMap<K, V> orig) {
59          return new MMap<>(new HashMap<>(orig.delegate));
60      }
61  
62      public static <K, V> MMap<K, Collection<V>> copyWithKey(K key, MMap<K, Collection<V>> orig) {
63          HashMap<K, Collection<V>> delegateLocal = new HashMap<>(orig.delegate);
64          delegateLocal.computeIfPresent(key, (k, v) -> new ArrayList<>(v));
65          return new MMap<>(delegateLocal);
66      }
67  
68      protected final HashMap<K, V> delegate;
69  
70      private MMap(HashMap<K, V> delegate) {
71          this.delegate = delegate;
72      }
73  
74      public boolean containsKey(K key) {
75          return delegate.containsKey(key);
76      }
77  
78      public V get(K key) {
79          return delegate.get(key);
80      }
81  
82      public V put(K key, V value) {
83          return delegate.put(key, value);
84      }
85  
86      public MMap<K, V> done() {
87          return new DoneMMap<>(delegate);
88      }
89  
90      @Override
91      public int hashCode() {
92          throw new IllegalStateException("MMap is not done yet");
93      }
94  
95      @Override
96      public boolean equals(Object o) {
97          throw new IllegalStateException("MMap is not done yet");
98      }
99  
100     private static class DoneMMap<K, V> extends MMap<K, V> {
101         private final int hashCode;
102 
103         private DoneMMap(HashMap<K, V> delegate) {
104             super(delegate);
105             this.hashCode = delegate.hashCode();
106         }
107 
108         @Override
109         public V put(K key, V value) {
110             throw new IllegalStateException("Done MMap is immutable");
111         }
112 
113         @Override
114         public MMap<K, V> done() {
115             return this;
116         }
117 
118         @Override
119         public int hashCode() {
120             return hashCode;
121         }
122 
123         @Override
124         public boolean equals(Object o) {
125             if (!(o instanceof MMap)) {
126                 return false;
127             }
128             MMap<?, ?> other = (MMap<?, ?>) o;
129             return delegate.equals(other.delegate);
130         }
131     }
132 }