1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.collection.LinkedMultiValueMap; 13 14 import hunt.collection.Collection; 15 import hunt.collection.LinkedHashMap; 16 import hunt.collection.LinkedList; 17 import hunt.collection.List; 18 import hunt.collection.MultiValueMap; 19 import hunt.collection.Map; 20 import hunt.collection.Set; 21 import hunt.Object; 22 import hunt.util.ObjectUtils; 23 24 import std.range; 25 26 /** 27 * Simple implementation of {@link MultiValueMap} that wraps a {@link LinkedHashMap}, 28 * storing multiple values in a {@link LinkedList}. 29 * 30 * <p>This Map implementation is generally not thread-safe. It is primarily designed 31 * for data structures exposed from request objects, for use in a single thread only. 32 * 33 * @author Arjen Poutsma 34 * @author Juergen Hoeller 35 */ 36 class LinkedMultiValueMap(K, V) : MultiValueMap!(K, V) { 37 38 private Map!(K, List!(V)) targetMap; 39 40 41 /** 42 * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap}. 43 */ 44 this() { 45 this.targetMap = new LinkedHashMap!(K, List!(V))(); 46 } 47 48 /** 49 * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap} 50 * with the given initial capacity. 51 * @param initialCapacity the initial capacity 52 */ 53 this(int initialCapacity) { 54 this.targetMap = new LinkedHashMap!(K, List!(V))(initialCapacity); 55 } 56 57 /** 58 * Copy constructor: Create a new LinkedMultiValueMap with the same mappings as 59 * the specified Map. Note that this will be a shallow copy; its value-holding 60 * List entries will get reused and therefore cannot get modified independently. 61 * @param otherMap the Map whose mappings are to be placed in this Map 62 * @see #clone() 63 * @see #deepCopy() 64 */ 65 this(Map!(K, List!(V)) otherMap) { 66 this.targetMap = new LinkedHashMap!(K, List!(V))(otherMap); 67 } 68 69 70 // MultiValueMap implementation 71 72 override 73 V getFirst(K key) { 74 List!(V) values = this.targetMap.get(key); 75 return (values !is null ? values.get(0) : null); 76 } 77 78 override 79 void add(K key, V value) { 80 List!(V) values = this.targetMap.computeIfAbsent(key, k => new LinkedList!(V)()); 81 values.add(value); 82 } 83 84 override 85 void addAll(K key, List!(V) values) { 86 List!(V) currentValues = this.targetMap.computeIfAbsent(key, k => new LinkedList!(V)()); 87 currentValues.addAll(values); 88 } 89 90 void addAll(Map!(K, List!V) values) { 91 foreach (K key, List!V value ; values) { 92 addAll(key, value); 93 } 94 } 95 96 override 97 void set(K key, V value) { 98 List!(V) values = new LinkedList!(V)(); 99 values.add(value); 100 this.targetMap.put(key, values); 101 } 102 103 override 104 void setAll(Map!(K, V) values) { 105 foreach (K key, V value ; values) 106 this.set(key, value); 107 } 108 109 override 110 Map!(K, V) toSingleValueMap() { 111 LinkedHashMap!(K, V) singleValueMap = new LinkedHashMap!(K, V)(this.targetMap.size()); 112 foreach (K key, List!(V) value ; this.targetMap) 113 singleValueMap.put(key, value.get(0)); 114 115 return singleValueMap; 116 } 117 118 119 // Map implementation 120 121 override 122 int size() { 123 return this.targetMap.size(); 124 } 125 126 override 127 bool isEmpty() { 128 return this.targetMap.isEmpty(); 129 } 130 131 override 132 bool containsKey(K key) { 133 return this.targetMap.containsKey(key); 134 } 135 136 override 137 bool containsValue(List!(V) value) { 138 return this.targetMap.containsValue(value); 139 } 140 141 List!(V) opIndex(K key) { 142 return get(key); 143 } 144 145 override 146 List!(V) get(K key) { 147 return this.targetMap.get(key); 148 } 149 150 override 151 List!(V) put(K key, List!(V) value) { 152 return this.targetMap.put(key, value); 153 } 154 155 List!(V) putIfAbsent(K key, List!(V) value) { 156 List!(V) v; 157 158 if(!containsKey(key)) 159 v = put(key, value); 160 161 return v; 162 } 163 164 override 165 List!(V) remove(K key) { 166 return this.targetMap.remove(key); 167 } 168 169 bool remove(K key, List!(V) value){ 170 List!(V) curValue = get(key); 171 if(curValue != value || !containsKey(key)) 172 return false; 173 remove(key); 174 return true; 175 } 176 177 override 178 void putAll(Map!(K, List!(V)) map) { 179 this.targetMap.putAll(map); 180 } 181 182 override 183 void clear() { 184 this.targetMap.clear(); 185 } 186 187 bool replace(K key, List!(V) oldValue, List!(V) newValue) { 188 List!(V) curValue = get(key); 189 if(curValue != oldValue || !containsKey(key)){ 190 return false; 191 } 192 put(key, newValue); 193 return true; 194 } 195 196 List!(V) replace(K key, List!(V) value) { 197 List!(V) curValue; 198 if (containsKey(key)) { 199 curValue = put(key, value); 200 } 201 return curValue; 202 } 203 204 int opApply(scope int delegate(ref K, ref List!(V)) dg) { 205 return this.targetMap.opApply(dg); 206 } 207 208 int opApply(scope int delegate(MapEntry!(K, List!(V)) entry) dg) { 209 return this.targetMap.opApply(dg); 210 } 211 212 InputRange!K byKey() { 213 return this.targetMap.byKey(); 214 } 215 216 InputRange!(List!(V)) byValue() { 217 return this.targetMap.byValue(); 218 } 219 220 // override 221 // Set!(K) keySet() { 222 // return this.targetMap.keySet(); 223 // } 224 225 // override 226 List!(V)[] values() { 227 return this.targetMap.values(); 228 } 229 230 // override 231 // Set<Entry!(K, List!(V))> entrySet() { 232 // return this.targetMap.entrySet(); 233 // } 234 235 236 /** 237 * Create a deep copy of this Map. 238 * @return a copy of this Map, including a copy of each value-holding List entry 239 * @since 4.2 240 * @see #clone() 241 */ 242 LinkedMultiValueMap!(K, V) deepCopy() { 243 LinkedMultiValueMap!(K, V) copy = new LinkedMultiValueMap!(K, V)(this.targetMap.size()); 244 foreach(K key, List!(V) value; this.targetMap) { 245 copy.put(key, new LinkedList!(V)(value)); 246 } 247 return copy; 248 } 249 250 /** 251 * Create a regular copy of this Map. 252 * @return a shallow copy of this Map, reusing this Map's value-holding List entries 253 * @since 4.2 254 * @see LinkedMultiValueMap#LinkedMultiValueMap(Map) 255 * @see #deepCopy() 256 */ 257 258 mixin CloneMemberTemplate!(typeof(this)); 259 260 bool opEquals(IObject o) { 261 return opEquals(cast(Object)o); 262 } 263 264 override bool opEquals(Object obj) { 265 return this.targetMap == obj; 266 } 267 268 override size_t toHash() @trusted nothrow { 269 return this.targetMap.toHash; 270 } 271 272 override string toString() { 273 return this.targetMap.toString(); 274 } 275 276 }