1
1
package stroom .meta .api ;
2
2
3
- import java .io .Serializable ;
4
3
import java .util .Collection ;
5
4
import java .util .HashMap ;
6
5
import java .util .HashSet ;
7
6
import java .util .Locale ;
8
7
import java .util .Map ;
9
8
import java .util .Objects ;
10
9
import java .util .Set ;
11
- import java .util .function .Function ;
12
10
import java .util .stream .Collectors ;
13
11
14
12
/**
15
13
* String hash map that does not care about key case.
16
14
*/
17
15
class CIStringHashMap implements Map <String , String > {
18
16
19
- private final HashMap <CIString , String > map = new HashMap <>();
17
+ private final HashMap <String , KV > map = new HashMap <>();
20
18
21
19
@ Override
22
20
public void clear () {
@@ -25,50 +23,69 @@ public void clear() {
25
23
26
24
@ Override
27
25
public boolean containsKey (final Object key ) {
28
- return map .containsKey (new CIString (( String ) key ));
26
+ return map .containsKey (toLowerCase ( key ));
29
27
}
30
28
31
29
@ Override
32
30
public boolean containsValue (final Object value ) {
33
- return map .containsValue (value );
31
+ return map .entrySet ().stream ().anyMatch (entry -> Objects .equals (entry .getValue ().getValue (), value ));
32
+ }
33
+
34
+ private String toLowerCase (final Object key ) {
35
+ return ((String ) key ).toLowerCase (Locale .ROOT );
36
+ }
37
+
38
+ private String getKey (final KV kv ) {
39
+ if (kv == null ) {
40
+ return null ;
41
+ }
42
+ return kv .getKey ();
43
+ }
44
+
45
+ private String getValue (final KV kv ) {
46
+ if (kv == null ) {
47
+ return null ;
48
+ }
49
+ return kv .getValue ();
34
50
}
35
51
36
52
@ Override
37
53
public String get (final Object key ) {
38
- return map .get (new CIString ((String ) key ));
54
+ return getValue (map .get (toLowerCase (key )));
55
+ }
56
+
57
+ public String getKey (final String key ) {
58
+ return getKey (map .get (toLowerCase (key )));
59
+ }
60
+
61
+ public KV getEntry (final String key ) {
62
+ return map .get (toLowerCase (key ));
39
63
}
40
64
41
65
@ Override
42
66
public String getOrDefault (final Object key , final String defaultVal ) {
43
- final String val = map .get (new CIString (( String ) key ));
44
- return val == null
67
+ final KV kv = map .get (toLowerCase ( key ));
68
+ return kv == null
45
69
? defaultVal
46
- : val ;
70
+ : kv . getKey () ;
47
71
}
48
72
49
73
@ Override
50
74
public boolean isEmpty () {
51
75
return map .isEmpty ();
52
76
}
53
77
54
- public String computeIfAbsent (final String key , final Function <String , String > mappingFunction ) {
55
- return map .computeIfAbsent (new CIString (key ), k -> mappingFunction .apply (k .key ));
56
- }
57
-
58
78
@ Override
59
79
public String put (final String key , String value ) {
60
80
if (value != null ) {
61
81
value = value .trim ();
62
82
}
63
- final CIString newKey = new CIString (key );
64
- final String oldValue = map .remove (newKey );
65
- map .put (newKey , value );
66
- return oldValue ;
83
+ return getValue (map .put (toLowerCase (key ), new KV (key , value )));
67
84
}
68
85
69
86
@ Override
70
87
public String remove (final Object key ) {
71
- return map .remove (new CIString (( String ) key ));
88
+ return getValue ( map .remove (toLowerCase ( key ) ));
72
89
}
73
90
74
91
@ Override
@@ -82,9 +99,9 @@ public int size() {
82
99
*/
83
100
@ Override
84
101
public Set <Entry <String , String >> entrySet () {
85
- final Set <Entry <String , String >> rtnSet = new HashSet <>();
86
- for (final Entry < CIString , String > entry : map .entrySet ()) {
87
- rtnSet .add (new CIEntryAdaptor ( entry ));
102
+ final Set <Entry <String , String >> rtnSet = new HashSet <>(map . size () );
103
+ for (final KV kv : map .values ()) {
104
+ rtnSet .add (Map . entry ( kv . getKey (), kv . getValue () ));
88
105
}
89
106
return rtnSet ;
90
107
}
@@ -95,9 +112,9 @@ public Set<Entry<String, String>> entrySet() {
95
112
*/
96
113
@ Override
97
114
public Set <String > keySet () {
98
- final Set <String > rtnSet = new HashSet <>();
99
- for (final CIString entry : map .keySet ()) {
100
- rtnSet .add (entry . key );
115
+ final Set <String > rtnSet = new HashSet <>(map . size () );
116
+ for (final KV kv : map .values ()) {
117
+ rtnSet .add (kv . getKey () );
101
118
}
102
119
return rtnSet ;
103
120
}
@@ -111,7 +128,7 @@ public void putAll(final Map<? extends String, ? extends String> m) {
111
128
112
129
@ Override
113
130
public Collection <String > values () {
114
- return map .values ();
131
+ return map .values (). stream (). map ( KV :: getValue ). collect ( Collectors . toSet ()) ;
115
132
}
116
133
117
134
@ Override
@@ -141,32 +158,36 @@ public int hashCode() {
141
158
* will be left in their original case.
142
159
*/
143
160
public Map <String , String > asMap (final boolean normaliseKeys ) {
144
- final Function <Entry <CIString , String >, String > keyMapper = normaliseKeys
145
- ? entry -> entry .getKey ().lowerKey
146
- : entry -> entry .getKey ().key ;
147
-
148
- return map .entrySet ()
161
+ if (normaliseKeys ) {
162
+ return map
163
+ .values ()
164
+ .stream ()
165
+ .collect (Collectors .toMap (kv -> kv .getKey ().toLowerCase (Locale .ROOT ), KV ::getValue ));
166
+ }
167
+ return map
168
+ .values ()
149
169
.stream ()
150
- .collect (Collectors .toMap (keyMapper , Entry ::getValue ));
170
+ .collect (Collectors .toMap (KV :: getKey , KV ::getValue ));
151
171
}
152
172
153
- // --------------------------------------------------------------------------------
154
-
155
-
156
- protected static class CIString implements Comparable <CIString >, Serializable {
173
+ public static class KV {
157
174
158
175
private final String key ;
159
- private final String lowerKey ;
176
+ private final String value ;
160
177
161
- CIString (final String key ) {
162
- this .key = key . trim () ;
163
- this .lowerKey = this . key . toLowerCase ( Locale . ENGLISH ) ;
178
+ public KV (final String key , final String value ) {
179
+ this .key = key ;
180
+ this .value = value ;
164
181
}
165
182
166
183
public String getKey () {
167
184
return key ;
168
185
}
169
186
187
+ public String getValue () {
188
+ return value ;
189
+ }
190
+
170
191
@ Override
171
192
public boolean equals (final Object o ) {
172
193
if (this == o ) {
@@ -175,51 +196,18 @@ public boolean equals(final Object o) {
175
196
if (o == null || getClass () != o .getClass ()) {
176
197
return false ;
177
198
}
178
- final CIString ciString = (CIString ) o ;
179
- return lowerKey .equals (ciString . lowerKey );
199
+ final KV kv = (KV ) o ;
200
+ return Objects .equals (value , kv . value );
180
201
}
181
202
182
203
@ Override
183
204
public int hashCode () {
184
- return lowerKey .hashCode ();
185
- }
186
-
187
- @ Override
188
- public int compareTo (final CIString o ) {
189
- return lowerKey .compareTo (o .lowerKey );
205
+ return Objects .hashCode (value );
190
206
}
191
207
192
208
@ Override
193
209
public String toString () {
194
- return key ;
195
- }
196
- }
197
-
198
-
199
- // --------------------------------------------------------------------------------
200
-
201
-
202
- private static class CIEntryAdaptor implements Entry <String , String > {
203
-
204
- private final Entry <CIString , String > realEntry ;
205
-
206
- private CIEntryAdaptor (final Entry <CIString , String > realEntry ) {
207
- this .realEntry = realEntry ;
208
- }
209
-
210
- @ Override
211
- public String getKey () {
212
- return realEntry .getKey ().key ;
213
- }
214
-
215
- @ Override
216
- public String getValue () {
217
- return realEntry .getValue ();
218
- }
219
-
220
- @ Override
221
- public String setValue (final String value ) {
222
- return realEntry .setValue (value );
210
+ return value ;
223
211
}
224
212
}
225
213
}
0 commit comments