summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/esodata/PushdownMap.java
blob: 4b758e375b5164b729e9da970f179ff851a7031f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package bjc.utils.esodata;

import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.IList;
import bjc.utils.funcdata.IMap;

import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * A variant of a map where inserting a duplicate key shadows the existing value
 * instead of replacing it.
 * 
 * @author EVE
 *
 * @param <KeyType>
 *                The key of the map.
 * @param <ValueType>
 *                The values in the map.
 */
public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
	private IMap<KeyType, Stack<ValueType>> backing;

	/**
	 * Create a new empty stack-based map.
	 */
	public PushdownMap() {
		backing = new FunctionalMap<>();
	}

	private PushdownMap(IMap<KeyType, Stack<ValueType>> back) {
		backing = back;
	}

	@Override
	public void clear() {
		backing.clear();
	}

	@Override
	public boolean containsKey(KeyType key) {
		return backing.containsKey(key);
	}

	@Override
	public IMap<KeyType, ValueType> extend() {
		return new PushdownMap<>(backing.extend());
	}

	@Override
	public void forEach(BiConsumer<KeyType, ValueType> action) {
		backing.forEach((key, stk) -> action.accept(key, stk.top()));
	}

	@Override
	public void forEachKey(Consumer<KeyType> action) {
		backing.forEachKey(action);
	}

	@Override
	public void forEachValue(Consumer<ValueType> action) {
		backing.forEachValue(stk -> action.accept(stk.top()));
	}

	@Override
	public ValueType get(KeyType key) {
		return backing.get(key).top();
	}

	@Override
	public int getSize() {
		return backing.getSize();
	}

	@Override
	public IList<KeyType> keyList() {
		return backing.keyList();
	}

	@Override
	public <V2> IMap<KeyType, V2> mapValues(Function<ValueType, V2> transformer) {
		throw new UnsupportedOperationException("Cannot transform pushdown maps.");
	}

	@Override
	public ValueType put(KeyType key, ValueType val) {
		if(backing.containsKey(key)) {
			Stack<ValueType> stk = backing.get(key);

			ValueType vl = stk.top();

			stk.push(val);

			return vl;
		} else {
			Stack<ValueType> stk = new SimpleStack<>();

			stk.push(val);

			return null;
		}
	}

	@Override
	public ValueType remove(KeyType key) {
		Stack<ValueType> stk = backing.get(key);

		if(stk.size() > 1) {
			return stk.pop();
		} else {
			return backing.remove(key).top();
		}
	}

	@Override
	public IList<ValueType> valueList() {
		return backing.valueList().map(stk -> stk.top());
	}
}