diff options
Diffstat (limited to 'subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java')
-rw-r--r-- | subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java new file mode 100644 index 00000000..1ce1d2c9 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java | |||
@@ -0,0 +1,216 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd. | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.util; | ||
10 | |||
11 | import java.util.stream.Stream; | ||
12 | |||
13 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType; | ||
14 | |||
15 | /** | ||
16 | * A multi-map that associates sets / multisets / delta sets of values to each key. | ||
17 | * | ||
18 | * <p> Implementors must provide semantic (not identity-based) hashCode() and equals() using the static helpers {@link #hashCode(IMultiLookup)} and {@link #equals(IMultiLookup, Object)} here. | ||
19 | * | ||
20 | * @author Gabor Bergmann | ||
21 | * @since 2.0 | ||
22 | * @noimplement This interface is not intended to be implemented by clients. | ||
23 | */ | ||
24 | public interface IMultiLookup<Key, Value> { | ||
25 | |||
26 | /** | ||
27 | * Returns true if this collection is empty, false otherwise. | ||
28 | * @since 2.2 | ||
29 | */ | ||
30 | boolean isEmpty(); | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Returns true if there are any values associated with the given key. | ||
35 | * @param key a key for which associated values are sought | ||
36 | * @since 2.3 | ||
37 | */ | ||
38 | boolean lookupExists(Key key); | ||
39 | |||
40 | /** | ||
41 | * Returns a (read-only) bucket of values associated with the given key. | ||
42 | * Clients must not modify the returned bucket. | ||
43 | * @param key a key for which associated values are sought | ||
44 | * @return null if key not found, a bucket of values otherwise | ||
45 | */ | ||
46 | IMemoryView<Value> lookup(Key key); | ||
47 | |||
48 | /** | ||
49 | * Returns a (read-only) bucket of values associated with the given key. | ||
50 | * Clients must not modify the returned bucket. | ||
51 | * @param key a key for which associated values are sought | ||
52 | * @return a bucket of values, never null | ||
53 | */ | ||
54 | default IMemoryView<Value> lookupOrEmpty(Key key) { | ||
55 | IMemoryView<Value> bucket = lookup(key); | ||
56 | return bucket == null ? EmptyMemory.instance() : bucket; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Returns a (read-only) bucket of values associated with the given key, while simultaneously removing them. | ||
61 | * Clients must not modify the returned bucket. | ||
62 | * @param key a key for which associated values are sought | ||
63 | * @return a bucket of values, never null | ||
64 | * @since 2.3 | ||
65 | */ | ||
66 | IMemoryView<Value> lookupAndRemoveAll(Key key); | ||
67 | |||
68 | /** | ||
69 | * Returns a (read-only) bucket of values associated with the given key, which can be of any type. | ||
70 | * Clients must not modify the returned bucket. | ||
71 | * @param key a key for which associated values are sought (may or may not be of Key type) | ||
72 | * @return null if key not found, a bucket of values otherwise | ||
73 | */ | ||
74 | IMemoryView<Value> lookupUnsafe(Object key); | ||
75 | |||
76 | /** | ||
77 | * Returns a (read-only) bucket of values associated with the given key. | ||
78 | * Clients must not modify the returned bucket. | ||
79 | * @param key a key for which associated values are sought (may or may not be of Key type) | ||
80 | * @return a bucket of values, never null | ||
81 | */ | ||
82 | default IMemoryView<Value> lookupUnsafeOrEmpty(Object key) { | ||
83 | IMemoryView<Value> bucket = lookupUnsafe(key); | ||
84 | return bucket == null ? EmptyMemory.instance() : bucket; | ||
85 | } | ||
86 | |||
87 | |||
88 | |||
89 | /** | ||
90 | * @return the set of distinct keys that have values associated. | ||
91 | */ | ||
92 | Iterable<Key> distinctKeys(); | ||
93 | |||
94 | /** | ||
95 | * @return the set of distinct keys that have values associated. | ||
96 | * @since 2.3 | ||
97 | */ | ||
98 | Stream<Key> distinctKeysStream(); | ||
99 | |||
100 | /** | ||
101 | * @return the number of distinct keys that have values associated. | ||
102 | */ | ||
103 | int countKeys(); | ||
104 | |||
105 | /** | ||
106 | * Iterates once over each distinct value. | ||
107 | */ | ||
108 | Iterable<Value> distinctValues(); | ||
109 | |||
110 | /** | ||
111 | * Iterates once over each distinct value. | ||
112 | * @since 2.3 | ||
113 | */ | ||
114 | Stream<Value> distinctValuesStream(); | ||
115 | |||
116 | |||
117 | |||
118 | /** | ||
119 | * How significant was the change? * | ||
120 | * @author Gabor Bergmann | ||
121 | */ | ||
122 | public enum ChangeGranularity { | ||
123 | /** | ||
124 | * First key-value pair with given key inserted, or last pair with given key deleted. | ||
125 | * (In case of delta maps, also if last negative key-value pair with given key neutralized.) | ||
126 | */ | ||
127 | KEY, | ||
128 | /** | ||
129 | * First occurrence of given key-value pair inserted, or last occurrence of the pair deleted, while key still has values associated. | ||
130 | * (In case of delta maps, also if last negative occurrence of key-value pair neutralized.) | ||
131 | */ | ||
132 | VALUE, | ||
133 | /** | ||
134 | * Duplicate key-value pair inserted or deleted. | ||
135 | */ | ||
136 | DUPLICATE | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * Adds key-value pair to the lookup structure, or fails if not possible. | ||
141 | * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}), | ||
142 | * the operation throws an {@link IllegalStateException}. | ||
143 | * @return the granularity of the change | ||
144 | * @throws IllegalStateException if addition would cause duplication that is not permitted | ||
145 | */ | ||
146 | public ChangeGranularity addPair(Key key, Value value); | ||
147 | /** | ||
148 | * Adds key-value pair to the lookup structure. | ||
149 | * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}), | ||
150 | * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned. | ||
151 | * @return the granularity of the change, or {@link ChangeGranularity#DUPLICATE} if addition would result in a duplicate and therefore ignored | ||
152 | * @since 2.3 | ||
153 | */ | ||
154 | public ChangeGranularity addPairOrNop(Key key, Value value); | ||
155 | /** | ||
156 | * Removes key-value pair from the lookup structure, or fails if not possible. | ||
157 | * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type | ||
158 | * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}), an {@link IllegalStateException} is thrown. | ||
159 | * @return the granularity of the change | ||
160 | * @throws IllegalStateException if removing non-existing element that is not permitted | ||
161 | */ | ||
162 | public ChangeGranularity removePair(Key key, Value value); | ||
163 | /** | ||
164 | * Removes key-value pair from the lookup structure. | ||
165 | * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type | ||
166 | * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}), | ||
167 | * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned. | ||
168 | * @return the granularity of the change | ||
169 | * @throws IllegalStateException if removing non-existing element that is not permitted | ||
170 | * @since 2.3 | ||
171 | */ | ||
172 | public ChangeGranularity removePairOrNop(Key key, Value value); | ||
173 | |||
174 | /** | ||
175 | * Updates multiplicity of key-value pair by a positive amount. | ||
176 | * | ||
177 | * <p> PRE: count > 0 | ||
178 | * | ||
179 | * @return the granularity of the change | ||
180 | * @throws IllegalStateException if addition would cause duplication that is not permitted | ||
181 | */ | ||
182 | public ChangeGranularity addPairPositiveMultiplicity(Key key, Value value, int count); | ||
183 | |||
184 | /** | ||
185 | * Empties out the lookup structure. | ||
186 | */ | ||
187 | public void clear(); | ||
188 | |||
189 | /** | ||
190 | * Provides semantic equality comparison. | ||
191 | */ | ||
192 | public static <Key, Value> boolean equals(IMultiLookup<Key, Value> self, Object obj) { | ||
193 | if (obj instanceof IMultiLookup<?, ?>) { | ||
194 | IMultiLookup<?, ?> other = (IMultiLookup<?, ?>) obj; | ||
195 | if (other.countKeys() != self.countKeys()) return false; | ||
196 | for (Object key : other.distinctKeys()) { | ||
197 | if (! other.lookupUnsafe(key).equals(self.lookupUnsafe(key))) | ||
198 | return false; | ||
199 | } | ||
200 | return true; | ||
201 | } | ||
202 | return false; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Provides semantic hashCode() comparison. | ||
207 | */ | ||
208 | public static <Key, Value> int hashCode(IMultiLookup<Key, Value> memory) { | ||
209 | int hashCode = 0; | ||
210 | for (Key key : memory.distinctKeys()) { | ||
211 | hashCode += key.hashCode() ^ memory.lookup(key).hashCode(); | ||
212 | } | ||
213 | return hashCode; | ||
214 | } | ||
215 | |||
216 | } | ||