Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
HashMap.cs
Go to the documentation of this file.
1 /*
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements. See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership. The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied. See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20 */
21 
22 using System;
23 using System.Collections;
24 using System.Collections.Generic;
25 
26 namespace Lucene.Net.Support
27 {
28  /// <summary>
29  /// A C# emulation of the <a href="http://download.oracle.com/javase/1,5.0/docs/api/java/util/HashMap.html">Java Hashmap</a>
30  /// <para>
31  /// A <see cref="Dictionary{TKey, TValue}" /> is a close equivalent to the Java
32  /// Hashmap. One difference java implementation of the class is that
33  /// the Hashmap supports both null keys and values, where the C# Dictionary
34  /// only supports null values not keys. Also, <c>V Get(TKey)</c>
35  /// method in Java returns null if the key doesn't exist, instead of throwing
36  /// an exception. This implementation doesn't throw an exception when a key
37  /// doesn't exist, it will return null. This class is slower than using a
38  /// <see cref="Dictionary{TKey, TValue}"/>, because of extra checks that have to be
39  /// done on each access, to check for null.
40  /// </para>
41  /// <para>
42  /// <b>NOTE:</b> This class works best with nullable types. default(T) is returned
43  /// when a key doesn't exist in the collection (this being similar to how Java returns
44  /// null). Therefore, if the expected behavior of the java code is to execute code
45  /// based on if the key exists, when the key is an integer type, it will return 0 instead of null.
46  /// </para>
47  /// <remaks>
48  /// Consider also implementing IDictionary, IEnumerable, and ICollection
49  /// like <see cref="Dictionary{TKey, TValue}" /> does, so HashMap can be
50  /// used in substituted in place for the same interfaces it implements.
51  /// </remaks>
52  /// </summary>
53  /// <typeparam name="TKey">The type of keys in the dictionary</typeparam>
54  /// <typeparam name="TValue">The type of values in the dictionary</typeparam>
55  [Serializable]
56  public class HashMap<TKey, TValue> : IDictionary<TKey, TValue>
57  {
58  internal IEqualityComparer<TKey> _comparer;
59  internal Dictionary<TKey, TValue> _dict;
60 
61  // Indicates if a null key has been assigned, used for iteration
62  private bool _hasNullValue;
63  // stores the value for the null key
64  private TValue _nullValue;
65  // Indicates the type of key is a non-nullable valuetype
66  private bool _isValueType;
67 
68  public HashMap()
69  : this(0)
70  { }
71 
72  public HashMap(IEqualityComparer<TKey> comparer)
73  : this(0, comparer)
74  {
75 
76  }
77 
78  public HashMap(int initialCapacity)
79  : this(initialCapacity, EqualityComparer<TKey>.Default)
80  {
81 
82  }
83 
84  public HashMap(int initialCapacity, IEqualityComparer<TKey> comparer)
85  {
86  _comparer = comparer;
87  _dict = new Dictionary<TKey, TValue>(initialCapacity, _comparer);
88  _hasNullValue = false;
89 
90  if (typeof(TKey).IsValueType)
91  {
92  _isValueType = Nullable.GetUnderlyingType(typeof(TKey)) == null;
93  }
94  }
95 
96  public HashMap(IEnumerable<KeyValuePair<TKey, TValue>> other)
97  : this(0)
98  {
99  foreach (var kvp in other)
100  {
101  Add(kvp.Key, kvp.Value);
102  }
103  }
104 
105  public bool ContainsValue(TValue value)
106  {
107  if (!_isValueType && _hasNullValue && _nullValue.Equals(value))
108  return true;
109 
110  return _dict.ContainsValue(value);
111  }
112 
113  #region Implementation of IEnumerable
114 
115  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
116  {
117  if (!_isValueType && _hasNullValue)
118  {
119  yield return new KeyValuePair<TKey, TValue>(default(TKey), _nullValue);
120  }
121  foreach (var kvp in _dict)
122  {
123  yield return kvp;
124  }
125  }
126 
127  IEnumerator IEnumerable.GetEnumerator()
128  {
129  return GetEnumerator();
130  }
131 
132  #endregion
133 
134  #region Implementation of ICollection<KeyValuePair<TKey,TValue>>
135 
136  void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
137  {
138  Add(item.Key, item.Value);
139  }
140 
141  public void Clear()
142  {
143  _hasNullValue = false;
144  _nullValue = default(TValue);
145  _dict.Clear();
146  }
147 
148  bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
149  {
150  if (!_isValueType && _comparer.Equals(item.Key, default(TKey)))
151  {
152  return _hasNullValue && EqualityComparer<TValue>.Default.Equals(item.Value, _nullValue);
153  }
154 
155  return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Contains(item);
156  }
157 
158  void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
159  {
160  ((ICollection<KeyValuePair<TKey, TValue>>) _dict).CopyTo(array, arrayIndex);
161  if(!_isValueType && _hasNullValue)
162  {
163  array[array.Length - 1] = new KeyValuePair<TKey, TValue>(default(TKey), _nullValue);
164  }
165  }
166 
167  public bool Remove(KeyValuePair<TKey, TValue> item)
168  {
169  if (!_isValueType && _comparer.Equals(item.Key, default(TKey)))
170  {
171  if (!_hasNullValue)
172  return false;
173 
174  _hasNullValue = false;
175  _nullValue = default(TValue);
176  return true;
177  }
178 
179  return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Remove(item);
180  }
181 
182  public int Count
183  {
184  get { return _dict.Count + (_hasNullValue ? 1 : 0); }
185  }
186 
187  public bool IsReadOnly
188  {
189  get { return false; }
190  }
191 
192  #endregion
193 
194  #region Implementation of IDictionary<TKey,TValue>
195 
196  public bool ContainsKey(TKey key)
197  {
198  if (!_isValueType && _comparer.Equals(key, default(TKey)))
199  {
200  if (_hasNullValue)
201  {
202  return true;
203  }
204  return false;
205  }
206 
207  return _dict.ContainsKey(key);
208  }
209 
210  public virtual void Add(TKey key, TValue value)
211  {
212  if (!_isValueType && _comparer.Equals(key, default(TKey)))
213  {
214  _hasNullValue = true;
215  _nullValue = value;
216  }
217  else
218  {
219  _dict[key] = value;
220  }
221  }
222 
223  public bool Remove(TKey key)
224  {
225  if (!_isValueType && _comparer.Equals(key, default(TKey)))
226  {
227  _hasNullValue = false;
228  _nullValue = default(TValue);
229  return true;
230  }
231  else
232  {
233  return _dict.Remove(key);
234  }
235  }
236 
237  public bool TryGetValue(TKey key, out TValue value)
238  {
239  if (!_isValueType && _comparer.Equals(key, default(TKey)))
240  {
241  if (_hasNullValue)
242  {
243  value = _nullValue;
244  return true;
245  }
246 
247  value = default(TValue);
248  return false;
249  }
250  else
251  {
252  return _dict.TryGetValue(key, out value);
253  }
254  }
255 
256  public TValue this[TKey key]
257  {
258  get
259  {
260  if (!_isValueType && _comparer.Equals(key, default(TKey)))
261  {
262  if (!_hasNullValue)
263  {
264  return default(TValue);
265  }
266  return _nullValue;
267  }
268  return _dict.ContainsKey(key) ? _dict[key] : default(TValue);
269  }
270  set { Add(key, value); }
271  }
272 
273  public ICollection<TKey> Keys
274  {
275  get
276  {
277  if (!_hasNullValue) return _dict.Keys;
278 
279  // Using a List<T> to generate an ICollection<TKey>
280  // would incur a costly copy of the dict's KeyCollection
281  // use out own wrapper instead
282  return new NullKeyCollection(_dict);
283  }
284  }
285 
286  public ICollection<TValue> Values
287  {
288  get
289  {
290  if (!_hasNullValue) return _dict.Values;
291 
292  // Using a List<T> to generate an ICollection<TValue>
293  // would incur a costly copy of the dict's ValueCollection
294  // use out own wrapper instead
295  return new NullValueCollection(_dict, _nullValue);
296  }
297  }
298 
299  #endregion
300 
301  #region NullValueCollection
302 
303  /// <summary>
304  /// Wraps a dictionary and adds the value
305  /// represented by the null key
306  /// </summary>
307  class NullValueCollection : ICollection<TValue>
308  {
309  private readonly TValue _nullValue;
310  private readonly Dictionary<TKey, TValue> _internalDict;
311 
312  public NullValueCollection(Dictionary<TKey, TValue> dict, TValue nullValue)
313  {
314  _internalDict = dict;
315  _nullValue = nullValue;
316  }
317 
318  #region Implementation of IEnumerable
319 
320  public IEnumerator<TValue> GetEnumerator()
321  {
322  yield return _nullValue;
323 
324  foreach (var val in _internalDict.Values)
325  {
326  yield return val;
327  }
328  }
329 
330  IEnumerator IEnumerable.GetEnumerator()
331  {
332  return GetEnumerator();
333  }
334 
335  #endregion
336 
337  #region Implementation of ICollection<TValue>
338 
339  public void CopyTo(TValue[] array, int arrayIndex)
340  {
341  throw new NotImplementedException("Implement as needed");
342  }
343 
344  public int Count
345  {
346  get { return _internalDict.Count + 1; }
347  }
348 
349  public bool IsReadOnly
350  {
351  get { return true; }
352  }
353 
354  #region Explicit Interface Methods
355 
356  void ICollection<TValue>.Add(TValue item)
357  {
358  throw new NotSupportedException();
359  }
360 
361  void ICollection<TValue>.Clear()
362  {
363  throw new NotSupportedException();
364  }
365 
366  bool ICollection<TValue>.Contains(TValue item)
367  {
368  throw new NotSupportedException();
369  }
370 
371  bool ICollection<TValue>.Remove(TValue item)
372  {
373  throw new NotSupportedException("Collection is read only!");
374  }
375  #endregion
376 
377  #endregion
378  }
379 
380  #endregion
381 
382  #region NullKeyCollection
383  /// <summary>
384  /// Wraps a dictionary's collection, adding in a
385  /// null key.
386  /// </summary>
387  class NullKeyCollection : ICollection<TKey>
388  {
389  private readonly Dictionary<TKey, TValue> _internalDict;
390 
391  public NullKeyCollection(Dictionary<TKey, TValue> dict)
392  {
393  _internalDict = dict;
394  }
395 
396  public IEnumerator<TKey> GetEnumerator()
397  {
398  yield return default(TKey);
399  foreach (var key in _internalDict.Keys)
400  {
401  yield return key;
402  }
403  }
404 
405  IEnumerator IEnumerable.GetEnumerator()
406  {
407  return GetEnumerator();
408  }
409 
410  public void CopyTo(TKey[] array, int arrayIndex)
411  {
412  throw new NotImplementedException("Implement this as needed");
413  }
414 
415  public int Count
416  {
417  get { return _internalDict.Count + 1; }
418  }
419 
420  public bool IsReadOnly
421  {
422  get { return true; }
423  }
424 
425  #region Explicit Interface Definitions
426  bool ICollection<TKey>.Contains(TKey item)
427  {
428  throw new NotSupportedException();
429  }
430 
431  void ICollection<TKey>.Add(TKey item)
432  {
433  throw new NotSupportedException();
434  }
435 
436  void ICollection<TKey>.Clear()
437  {
438  throw new NotSupportedException();
439  }
440 
441  bool ICollection<TKey>.Remove(TKey item)
442  {
443  throw new NotSupportedException();
444  }
445  #endregion
446  }
447  #endregion
448  }
449 }