Skip to content

Commit 2cc683f

Browse files
committed
Make maps provided to ModifyBakingResult mutable
1 parent da82e38 commit 2cc683f

File tree

2 files changed

+162
-1
lines changed

2 files changed

+162
-1
lines changed

src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public Object load(K key) throws Exception {
172172
}
173173
}
174174
});
175-
return Maps.asMap(input.keySet(), k -> {
175+
return new DynamicRegistryMap<>(input.keySet(),k -> {
176176
if (k != null) {
177177
Object value = bakedCache.getUnchecked(k);
178178
if (value == NULL_BAKED) {
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package org.embeddedt.modernfix.dynresources;
2+
3+
import com.google.common.collect.Collections2;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
import java.util.AbstractSet;
8+
import java.util.Collection;
9+
import java.util.Collections;
10+
import java.util.Iterator;
11+
import java.util.Map;
12+
import java.util.Set;
13+
import java.util.concurrent.ConcurrentHashMap;
14+
import java.util.function.Function;
15+
16+
/**
17+
* A map that behaves like Guava's Maps.asMap but allows for additional entries to be written that override the backing
18+
* map's entries.
19+
*/
20+
public final class DynamicRegistryMap<K, V> implements Map<K, V> {
21+
private static final Object NULL_OVERRIDE = new Object();
22+
private final Set<K> originalKeys;
23+
private final Function<K, V> fallbackGetter;
24+
private final ConcurrentHashMap<K, Object> overrides;
25+
private final EntrySet entrySet;
26+
27+
public DynamicRegistryMap(Set<K> originalKeys, Function<K, V> fallbackGetter) {
28+
this.originalKeys = originalKeys;
29+
this.fallbackGetter = fallbackGetter;
30+
this.overrides = new ConcurrentHashMap<>();
31+
this.entrySet = new EntrySet();
32+
}
33+
34+
@Override
35+
public int size() {
36+
return originalKeys.size();
37+
}
38+
39+
@Override
40+
public boolean isEmpty() {
41+
return originalKeys.isEmpty();
42+
}
43+
44+
@Override
45+
public boolean containsKey(Object o) {
46+
if (o == null) {
47+
return false;
48+
}
49+
var override = overrides.get(o);
50+
if (override == NULL_OVERRIDE) {
51+
return false;
52+
}
53+
return override != null || originalKeys.contains(o);
54+
}
55+
56+
@Override
57+
public boolean containsValue(Object o) {
58+
if (o == null || o == NULL_OVERRIDE) {
59+
return false;
60+
}
61+
return overrides.containsValue(o);
62+
}
63+
64+
@Override
65+
public V get(Object o) {
66+
Object value = overrides.get(o);
67+
if (value == NULL_OVERRIDE) {
68+
return null;
69+
} else if (value != null) {
70+
return (V) value;
71+
} else {
72+
return fallbackGetter.apply((K)o);
73+
}
74+
}
75+
76+
@Override
77+
public @Nullable V put(K k, V v) {
78+
if (v == null) {
79+
return remove(k);
80+
}
81+
overrides.put(k, v);
82+
return null;
83+
}
84+
85+
@Override
86+
public V remove(Object o) {
87+
overrides.put((K)o, NULL_OVERRIDE);
88+
return null;
89+
}
90+
91+
@Override
92+
public void putAll(@NotNull Map<? extends K, ? extends V> map) {
93+
map.forEach(this::put);
94+
}
95+
96+
@Override
97+
public void clear() {
98+
throw new UnsupportedOperationException();
99+
}
100+
101+
@Override
102+
public @NotNull Set<K> keySet() {
103+
return Collections.unmodifiableSet(originalKeys);
104+
}
105+
106+
@Override
107+
public @NotNull Collection<V> values() {
108+
return Collections2.transform(originalKeys, this::get);
109+
}
110+
111+
@Override
112+
public @NotNull Set<Entry<K, V>> entrySet() {
113+
return this.entrySet;
114+
}
115+
116+
private class ModelEntry implements Map.Entry<K, V> {
117+
private final K key;
118+
119+
private ModelEntry(K key) {
120+
this.key = key;
121+
}
122+
123+
@Override
124+
public K getKey() {
125+
return key;
126+
}
127+
128+
@Override
129+
public V getValue() {
130+
return get(key);
131+
}
132+
133+
@Override
134+
public V setValue(V value) {
135+
return put(key, value);
136+
}
137+
}
138+
139+
private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
140+
@Override
141+
public Iterator<Entry<K, V>> iterator() {
142+
var iterator = originalKeys.iterator();
143+
return new Iterator<>() {
144+
@Override
145+
public boolean hasNext() {
146+
return iterator.hasNext();
147+
}
148+
149+
@Override
150+
public Entry<K, V> next() {
151+
return new ModelEntry(iterator.next());
152+
}
153+
};
154+
}
155+
156+
@Override
157+
public int size() {
158+
return DynamicRegistryMap.this.size();
159+
}
160+
}
161+
}

0 commit comments

Comments
 (0)