1 /*
2 * *************************************************************************************************************************************************************
3 *
4 * TheseFoolishThings: Miscellaneous utilities
5 * http://tidalwave.it/projects/thesefoolishthings
6 *
7 * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8 *
9 * *************************************************************************************************************************************************************
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18 *
19 * *************************************************************************************************************************************************************
20 *
21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.util.impl;
27
28 import javax.annotation.Nonnegative;
29 import javax.annotation.Nonnull;
30 import javax.annotation.concurrent.Immutable;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.CopyOnWriteArrayList;
38 import java.util.concurrent.CopyOnWriteArraySet;
39 import java.util.function.BiConsumer;
40 import java.io.Serializable;
41 import it.tidalwave.util.Key;
42 import it.tidalwave.util.TypeSafeMultiMap;
43 import lombok.EqualsAndHashCode;
44
45 /***************************************************************************************************************************************************************
46 *
47 * @author Fabrizio Giudici
48 *
49 **************************************************************************************************************************************************************/
50 @Immutable @EqualsAndHashCode
51 public class TypeSafeHashMultiMap implements TypeSafeMultiMap, Serializable
52 {
53 private static final long serialVersionUID = 759233572056L;
54
55 @Nonnull
56 private final Map<Key<?>, Collection<?>> map;
57
58 /***********************************************************************************************************************************************************
59 * Creates a new instance from the given contents.
60 *
61 * @param map the contents
62 **********************************************************************************************************************************************************/
63 public TypeSafeHashMultiMap (@Nonnull final Map<? extends Key<?>, ? extends Collection<?>> map)
64 {
65 this(new HashMap<>(), true);
66 this.map.putAll(map);
67 }
68
69 /***********************************************************************************************************************************************************
70 **********************************************************************************************************************************************************/
71 /* package */ TypeSafeHashMultiMap (@Nonnull final Map<Key<?>, Collection<?>> map, final boolean ignored)
72 {
73 this.map = map;
74 }
75
76 /***********************************************************************************************************************************************************
77 * {@inheritDoc}
78 **********************************************************************************************************************************************************/
79 @Override @Nonnull @SuppressWarnings("unchecked")
80 public <T> Collection<T> get (@Nonnull final Key<T> key)
81 {
82 return containsKey(key) ? new CopyOnWriteArrayList<>((Collection<T>)map.get(key))
83 : new ArrayList<>();
84 }
85
86 /***********************************************************************************************************************************************************
87 * {@inheritDoc}
88 **********************************************************************************************************************************************************/
89 @Override
90 public boolean containsKey (@Nonnull final Key<?> key)
91 {
92 return map.containsKey(key);
93 }
94
95 /***********************************************************************************************************************************************************
96 * {@inheritDoc}
97 **********************************************************************************************************************************************************/
98 @Override @Nonnull
99 public <T> TypeSafeHashMultiMap with (@Nonnull final Key<T> key, @Nonnull final T value)
100 {
101 final var map = asMap();
102 final var values = get(key);
103 values.add(value);
104 map.put(key, values);
105 return new TypeSafeHashMultiMap(map);
106 }
107
108 /***********************************************************************************************************************************************************
109 * {@inheritDoc}
110 **********************************************************************************************************************************************************/
111 @Override @Nonnull
112 public Set<Key<?>> keySet()
113 {
114 return new CopyOnWriteArraySet<>(map.keySet());
115 }
116
117 /***********************************************************************************************************************************************************
118 * {@inheritDoc}
119 **********************************************************************************************************************************************************/
120 @Override @Nonnull
121 public Collection<Collection<?>> values()
122 {
123 return map.values();
124 }
125
126 /***********************************************************************************************************************************************************
127 * {@inheritDoc}
128 **********************************************************************************************************************************************************/
129 @Override @Nonnull
130 public Set<Map.Entry<Key<?>, Collection<?>>> entrySet()
131 {
132 return map.entrySet();
133 }
134
135 /***********************************************************************************************************************************************************
136 * {@inheritDoc}
137 **********************************************************************************************************************************************************/
138 @Override @Nonnull
139 public Iterator<Map.Entry<Key<?>, Collection<?>>> iterator()
140 {
141 return map.entrySet().iterator();
142 }
143
144 /***********************************************************************************************************************************************************
145 * {@inheritDoc}
146 **********************************************************************************************************************************************************/
147 @Override @Nonnegative
148 public int size()
149 {
150 return map.size();
151 }
152
153 /***********************************************************************************************************************************************************
154 * {@inheritDoc}
155 **********************************************************************************************************************************************************/
156 @Override @Nonnull
157 public Map<Key<?>, Collection<?>> asMap()
158 {
159 return new HashMap<>(map);
160 }
161
162 /***********************************************************************************************************************************************************
163 * {@inheritDoc}
164 **********************************************************************************************************************************************************/
165 @Override @SuppressWarnings("unchecked")
166 public <T> void forEach (@Nonnull final BiConsumer<? super Key<T>, ? super Collection<T>> action)
167 {
168 map.forEach((BiConsumer<? super Key<?>, ? super Collection<?>>)action);
169 }
170
171 /***********************************************************************************************************************************************************
172 * {@inheritDoc}
173 **********************************************************************************************************************************************************/
174 @Override @Nonnull
175 public String toString()
176 {
177 return map.toString();
178 }
179 }