You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2016/11/10 11:33:26 UTC
[15/58] [abbrv] lucenenet git commit: Added
Core.Support.LinkedHashMap + tests for supporting guaranteed insertion order
enumeration of an IDictionary structure.
Added Core.Support.LinkedHashMap + tests for supporting guaranteed insertion order enumeration of an IDictionary structure.
Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/7723e26d
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/7723e26d
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/7723e26d
Branch: refs/heads/grouping
Commit: 7723e26d74297b714fa3b67cef940f6072322296
Parents: 63fa4ca
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Sat Nov 5 19:52:23 2016 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Mon Nov 7 18:44:14 2016 +0700
----------------------------------------------------------------------
src/Lucene.Net.Core/Lucene.Net.csproj | 1 +
src/Lucene.Net.Core/Support/HashMap.cs | 49 +-
src/Lucene.Net.Core/Support/LinkedHashMap.cs | 523 +++++++++++++++++++
src/Lucene.Net.Tests/Lucene.Net.Tests.csproj | 1 +
.../core/Support/TestLinkedHashMap.cs | 359 +++++++++++++
5 files changed, 916 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/7723e26d/src/Lucene.Net.Core/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Lucene.Net.csproj b/src/Lucene.Net.Core/Lucene.Net.csproj
index 09915fb..5ce5f82 100644
--- a/src/Lucene.Net.Core/Lucene.Net.csproj
+++ b/src/Lucene.Net.Core/Lucene.Net.csproj
@@ -643,6 +643,7 @@
<Compile Include="Support\IdentityWeakReference.cs" />
<Compile Include="Support\IDictionaryExtensions.cs" />
<Compile Include="Support\LimitedConcurrencyLevelTaskScheduler.cs" />
+ <Compile Include="Support\LinkedHashMap.cs" />
<Compile Include="Support\ListExtensions.cs" />
<Compile Include="Support\LongBuffer.cs" />
<Compile Include="Support\LurchTable.cs" />
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/7723e26d/src/Lucene.Net.Core/Support/HashMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Support/HashMap.cs b/src/Lucene.Net.Core/Support/HashMap.cs
index 0fcf29a..ce3831d 100644
--- a/src/Lucene.Net.Core/Support/HashMap.cs
+++ b/src/Lucene.Net.Core/Support/HashMap.cs
@@ -22,6 +22,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Text;
namespace Lucene.Net.Support
{
@@ -52,6 +53,20 @@ namespace Lucene.Net.Support
/// </summary>
/// <typeparam name="TKey">The type of keys in the dictionary</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary</typeparam>
+ /// <remarks>
+ /// <h2>Unordered Dictionaries</h2>
+ /// <list type="bullet">
+ /// <item><see cref="Dictionary{TKey, TValue}"/> - use when order is not important and all keys are non-null.</item>
+ /// <item><see cref="HashMap{TKey, TValue}"/> - use when order is not important and support for a null key is required.</item>
+ /// </list>
+ /// <h2>Ordered Dictionaries</h2>
+ /// <list type="bullet">
+ /// <item><see cref="LinkedHashMap{TKey, TValue}"/> - use when you need to preserve entry insertion order. Keys are nullable.</item>
+ /// <item><see cref="SortedDictionary{TKey, TValue}"/> - use when you need natural sort order. Keys must be unique.</item>
+ /// <item><see cref="TreeDictionary{K, V}"/> - use when you need natural sort order. Keys may contain duplicates.</item>
+ /// <item><see cref="LurchTable{TKey, TValue}"/> - use when you need to sort by most recent access or most recent update. Works well for LRU caching.</item>
+ /// </list>
+ /// </remarks>
[Serializable]
public class HashMap<TKey, TValue> : IDictionary<TKey, TValue>
{
@@ -205,7 +220,7 @@ namespace Lucene.Net.Support
#region Implementation of IEnumerable
- public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
if (!_isValueType && _hasNullValue)
{
@@ -226,38 +241,38 @@ namespace Lucene.Net.Support
#region Implementation of ICollection<KeyValuePair<TKey,TValue>>
- void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+ public virtual void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
- public void Clear()
+ public virtual void Clear()
{
_hasNullValue = false;
_nullValue = default(TValue);
_dict.Clear();
}
- bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+ public virtual bool Contains(KeyValuePair<TKey, TValue> item)
{
if (!_isValueType && _comparer.Equals(item.Key, default(TKey)))
{
return _hasNullValue && EqualityComparer<TValue>.Default.Equals(item.Value, _nullValue);
}
- return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Contains(item);
+ return _dict.Contains(item);
}
- void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
- ((ICollection<KeyValuePair<TKey, TValue>>)_dict).CopyTo(array, arrayIndex);
+ _dict.CopyTo(array, arrayIndex);
if (!_isValueType && _hasNullValue)
{
array[array.Length - 1] = new KeyValuePair<TKey, TValue>(default(TKey), _nullValue);
}
}
- public bool Remove(KeyValuePair<TKey, TValue> item)
+ public virtual bool Remove(KeyValuePair<TKey, TValue> item)
{
if (!_isValueType && _comparer.Equals(item.Key, default(TKey)))
{
@@ -269,15 +284,15 @@ namespace Lucene.Net.Support
return true;
}
- return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Remove(item);
+ return _dict.Remove(item);
}
- public int Count
+ public virtual int Count
{
get { return _dict.Count + (_hasNullValue ? 1 : 0); }
}
- public bool IsReadOnly
+ public virtual bool IsReadOnly
{
get { return false; }
}
@@ -286,7 +301,7 @@ namespace Lucene.Net.Support
#region Implementation of IDictionary<TKey,TValue>
- public bool ContainsKey(TKey key)
+ public virtual bool ContainsKey(TKey key)
{
if (!_isValueType && _comparer.Equals(key, default(TKey)))
{
@@ -313,7 +328,7 @@ namespace Lucene.Net.Support
}
}
- public bool Remove(TKey key)
+ public virtual bool Remove(TKey key)
{
if (!_isValueType && _comparer.Equals(key, default(TKey)))
{
@@ -327,7 +342,7 @@ namespace Lucene.Net.Support
}
}
- public bool TryGetValue(TKey key, out TValue value)
+ public virtual bool TryGetValue(TKey key, out TValue value)
{
if (!_isValueType && _comparer.Equals(key, default(TKey)))
{
@@ -346,7 +361,7 @@ namespace Lucene.Net.Support
}
}
- public TValue this[TKey key]
+ public virtual TValue this[TKey key]
{
get
{
@@ -363,7 +378,7 @@ namespace Lucene.Net.Support
set { Add(key, value); }
}
- public ICollection<TKey> Keys
+ public virtual ICollection<TKey> Keys
{
get
{
@@ -376,7 +391,7 @@ namespace Lucene.Net.Support
}
}
- public ICollection<TValue> Values
+ public virtual ICollection<TValue> Values
{
get
{
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/7723e26d/src/Lucene.Net.Core/Support/LinkedHashMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Support/LinkedHashMap.cs b/src/Lucene.Net.Core/Support/LinkedHashMap.cs
new file mode 100644
index 0000000..5ae23ce
--- /dev/null
+++ b/src/Lucene.Net.Core/Support/LinkedHashMap.cs
@@ -0,0 +1,523 @@
+\ufeffusing System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Support
+{
+ /*
+ The MIT License (MIT)
+
+ Copyright (c) 2014 matarillo
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+ // Source: http://qiita.com/matarillo/items/c09e0f3e5a61f84a51e2
+ // 2016-11-05 - Shad Storhaug
+ // Modified from its original form to be backed by a
+ // HashMap rather than a Dictionary so it will support null keys.
+ // 2016-11-05 - Shad Storhaug
+ // Added KeyCollection and ValueCollection classes to prevent having to do
+ // an O(n) operation when calling the Keys or Values properties.
+
+ /// <summary>
+ /// LinkedHashMap is a specialized dictionary that preserves the entry order of elements.
+ /// Like a HashMap, there can be a <c>null</c> key, but it also guarantees that the enumeration
+ /// order of the elements are the same as insertion order, regardless of the number of add/remove/update
+ /// operations that are performed on it.
+ /// </summary>
+ /// <typeparam name="TKey">The type of keys in the dictionary</typeparam>
+ /// <typeparam name="TValue">The type of values in the dictionary</typeparam>
+ /// <remarks>
+ /// <h2>Unordered Dictionaries</h2>
+ /// <list type="bullet">
+ /// <item><see cref="Dictionary{TKey, TValue}"/> - use when order is not important and all keys are non-null.</item>
+ /// <item><see cref="HashMap{TKey, TValue}"/> - use when order is not important and support for a null key is required.</item>
+ /// </list>
+ /// <h2>Ordered Dictionaries</h2>
+ /// <list type="bullet">
+ /// <item><see cref="LinkedHashMap{TKey, TValue}"/> - use when you need to preserve entry insertion order. Keys are nullable.</item>
+ /// <item><see cref="SortedDictionary{TKey, TValue}"/> - use when you need natural sort order. Keys must be unique.</item>
+ /// <item><see cref="TreeDictionary{K, V}"/> - use when you need natural sort order. Keys may contain duplicates.</item>
+ /// <item><see cref="LurchTable{TKey, TValue}"/> - use when you need to sort by most recent access or most recent update. Works well for LRU caching.</item>
+ /// </list>
+ /// </remarks>
+ public class LinkedHashMap<TKey, TValue> : HashMap<TKey, TValue>, IDictionary<TKey, TValue>
+ {
+ private readonly HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> dict;
+ private readonly LinkedList<KeyValuePair<TKey, TValue>> list;
+
+ #region Constructors
+
+ public LinkedHashMap()
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ }
+
+ public LinkedHashMap(IEqualityComparer<TKey> comparer)
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(comparer);
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ }
+
+ public LinkedHashMap(int capacity)
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(capacity);
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ }
+
+ public LinkedHashMap(int capacity, IEqualityComparer<TKey> comparer)
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(capacity, comparer);
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ }
+
+ public LinkedHashMap(IEnumerable<KeyValuePair<TKey, TValue>> source)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException("source");
+ }
+ var countable = source as ICollection;
+ if (countable != null)
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(countable.Count);
+ }
+ else
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
+ }
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ foreach (var pair in source)
+ {
+ this[pair.Key] = pair.Value;
+ }
+ }
+
+ public LinkedHashMap(IEnumerable<KeyValuePair<TKey, TValue>> source, IEqualityComparer<TKey> comparer)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException("source");
+ }
+ var countable = source as ICollection;
+ if (countable != null)
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(countable.Count, comparer);
+ }
+ else
+ {
+ dict = new HashMap<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(comparer);
+ }
+ list = new LinkedList<KeyValuePair<TKey, TValue>>();
+ foreach (var pair in source)
+ {
+ this[pair.Key] = pair.Value;
+ }
+ }
+
+ #endregion
+
+ #region IEnumerable implementation
+
+ public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ return list.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IDictionary implementation
+
+ public override bool ContainsKey(TKey key)
+ {
+ return dict.ContainsKey(key);
+ }
+
+ public override void Add(TKey key, TValue value)
+ {
+ DoAdd(key, value);
+ }
+
+ private void DoAdd(TKey key, TValue value)
+ {
+ var pair = new KeyValuePair<TKey, TValue>(key, value);
+ var node = new LinkedListNode<KeyValuePair<TKey, TValue>>(pair);
+ dict.Add(key, node);
+ list.AddLast(node);
+ }
+
+ public override bool Remove(TKey key)
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> n;
+ if (!dict.TryGetValue(key, out n))
+ {
+ return false;
+ }
+ DoRemove(n);
+ return true;
+ }
+
+ private void DoRemove(LinkedListNode<KeyValuePair<TKey, TValue>> node)
+ {
+ dict.Remove(node.Value.Key);
+ list.Remove(node);
+ }
+
+ public override bool TryGetValue(TKey key, out TValue value)
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> n;
+ if (dict.TryGetValue(key, out n))
+ {
+ value = n.Value.Value;
+ return true;
+ }
+ value = default(TValue);
+ return false;
+ }
+
+ private bool TryGetNode(TKey key, TValue value, out LinkedListNode<KeyValuePair<TKey, TValue>> node)
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> n;
+ if (dict.TryGetValue(key, out n) && EqualityComparer<TValue>.Default.Equals(value, n.Value.Value))
+ {
+ node = n;
+ return true;
+ }
+ node = null;
+ return false;
+ }
+
+ public override TValue this[TKey key]
+ {
+ get
+ {
+ var node = dict[key];
+ if (node == null)
+ return default(TValue);
+
+ return node.Value.Value;
+ }
+ set
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> n;
+ if (!dict.TryGetValue(key, out n))
+ {
+ DoAdd(key, value);
+ return;
+ }
+ DoSet(n, key, value);
+ }
+ }
+
+ private void DoSet(LinkedListNode<KeyValuePair<TKey, TValue>> node, TKey key, TValue value)
+ {
+ var pair = new KeyValuePair<TKey, TValue>(key, value);
+ var newNode = new LinkedListNode<KeyValuePair<TKey, TValue>>(pair);
+ dict[key] = newNode;
+ list.AddAfter(node, newNode);
+ list.Remove(node);
+ }
+
+ public override ICollection<TKey> Keys
+ {
+ get
+ {
+ return new KeyCollection(this);
+ }
+ }
+
+ public override ICollection<TValue> Values
+ {
+ get
+ {
+ return new ValueCollection(this);
+ }
+ }
+
+ #endregion
+
+ #region ICollection implementation
+
+ public override void Clear()
+ {
+ dict.Clear();
+ list.Clear();
+ }
+
+ public override int Count
+ {
+ get { return dict.Count; }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public override void Add(KeyValuePair<TKey, TValue> item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ public override bool Contains(KeyValuePair<TKey, TValue> item)
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> pair;
+ return TryGetNode(item.Key, item.Value, out pair);
+ }
+
+ public override void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ list.CopyTo(array, arrayIndex);
+ }
+
+ public override bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ LinkedListNode<KeyValuePair<TKey, TValue>> node;
+ if (!TryGetNode(item.Key, item.Value, out node))
+ {
+ return false;
+ }
+ DoRemove(node);
+ return true;
+ }
+
+ #endregion
+
+ #region KeyCollection
+
+ internal class KeyCollection : ICollection<TKey>
+ {
+ private readonly LinkedHashMap<TKey, TValue> outerInstance;
+
+ public KeyCollection(LinkedHashMap<TKey, TValue> outerInstance)
+ {
+ this.outerInstance = outerInstance;
+ }
+
+ public int Count
+ {
+ get
+ {
+ return outerInstance.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public void Add(TKey item)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Clear()
+ {
+ outerInstance.Clear();
+ }
+
+ public bool Contains(TKey item)
+ {
+ return outerInstance.ContainsKey(item);
+ }
+
+ public void CopyTo(TKey[] array, int arrayIndex)
+ {
+ throw new NotImplementedException("Implement this as needed");
+ }
+
+ public IEnumerator<TKey> GetEnumerator()
+ {
+ return new KeyEnumerator(outerInstance.list.GetEnumerator());
+ }
+
+ public bool Remove(TKey item)
+ {
+ return outerInstance.Remove(item);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #region KeyEnumerator
+
+ internal class KeyEnumerator : IEnumerator<TKey>
+ {
+ private readonly IEnumerator<KeyValuePair<TKey, TValue>> innerEnumerator;
+
+ public KeyEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> innerEnumerator)
+ {
+ this.innerEnumerator = innerEnumerator;
+ }
+
+ public TKey Current
+ {
+ get
+ {
+ return innerEnumerator.Current.Key;
+ }
+ }
+
+ object IEnumerator.Current
+ {
+ get
+ {
+ return Current;
+ }
+ }
+
+ public void Dispose()
+ {
+ innerEnumerator.Dispose();
+ }
+
+ public bool MoveNext()
+ {
+ return innerEnumerator.MoveNext();
+ }
+
+ public void Reset()
+ {
+ innerEnumerator.Reset();
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+ #region ValueCollection
+
+ internal class ValueCollection : ICollection<TValue>
+ {
+ private readonly LinkedHashMap<TKey, TValue> outerInstance;
+
+ public ValueCollection(LinkedHashMap<TKey, TValue> outerInstance)
+ {
+ this.outerInstance = outerInstance;
+ }
+
+ public int Count
+ {
+ get
+ {
+ return outerInstance.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public void Add(TValue item)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Clear()
+ {
+ outerInstance.Clear();
+ }
+
+ public bool Contains(TValue item)
+ {
+ return outerInstance.ContainsValue(item);
+ }
+
+ public void CopyTo(TValue[] array, int arrayIndex)
+ {
+ throw new NotImplementedException("Implement this as needed");
+ }
+
+ public IEnumerator<TValue> GetEnumerator()
+ {
+ return new ValueEnumerator(outerInstance.list.GetEnumerator());
+ }
+
+ public bool Remove(TValue item)
+ {
+ throw new NotSupportedException();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+
+ internal class ValueEnumerator : IEnumerator<TValue>
+ {
+ private readonly IEnumerator<KeyValuePair<TKey, TValue>> innerEnumerator;
+
+ public ValueEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> innerEnumerator)
+ {
+ this.innerEnumerator = innerEnumerator;
+ }
+
+ public TValue Current
+ {
+ get
+ {
+ return innerEnumerator.Current.Value;
+ }
+ }
+
+ object IEnumerator.Current
+ {
+ get
+ {
+ return Current;
+ }
+ }
+
+ public void Dispose()
+ {
+ innerEnumerator.Dispose();
+ }
+
+ public bool MoveNext()
+ {
+ return innerEnumerator.MoveNext();
+ }
+
+ public void Reset()
+ {
+ innerEnumerator.Reset();
+ }
+ }
+ }
+
+
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/7723e26d/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
index 0b0ad11..9e6377e 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -484,6 +484,7 @@
<Compile Include="core\Support\C5\WeakViewList.cs" />
<Compile Include="core\Support\C5\Wrappers.cs" />
<Compile Include="core\Support\TestHashMap.cs" />
+ <Compile Include="core\Support\TestLinkedHashMap.cs" />
<Compile Include="core\Support\TestLongBuffer.cs" />
<Compile Include="core\Support\TestByteBuffer.cs" />
<Compile Include="core\Support\TestLurchTable.cs" />
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/7723e26d/src/Lucene.Net.Tests/core/Support/TestLinkedHashMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Support/TestLinkedHashMap.cs b/src/Lucene.Net.Tests/core/Support/TestLinkedHashMap.cs
new file mode 100644
index 0000000..73875e2
--- /dev/null
+++ b/src/Lucene.Net.Tests/core/Support/TestLinkedHashMap.cs
@@ -0,0 +1,359 @@
+\ufeffusing Lucene.Net.Attributes;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Support
+{
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ [TestFixture]
+ public class TestLinkedHashMap : TestHashMap
+ {
+ protected override HashMap<TKey, TValue> GetNewHashMap<TKey, TValue>()
+ {
+ return new LinkedHashMap<TKey, TValue>();
+ }
+
+ private IDictionary<FakeKey<int>, string> GetDefaultHashMap2()
+ {
+ var dict = GetNewHashMap<FakeKey<int>, string>();
+
+ dict[new FakeKey<int>(2)] = "MyString";
+ dict[new FakeKey<int>(0)] = "OtherString";
+ dict[new FakeKey<int>(5)] = "NumberFive";
+ dict[new FakeKey<int>(int.MaxValue)] = "Maximum";
+ dict[null] = "NullValue";
+ dict[new FakeKey<int>(int.MinValue)] = "Minimum";
+
+ return dict;
+ }
+
+ internal class FakeKey<T>
+ {
+ private readonly T key;
+
+ public FakeKey(T key)
+ {
+ this.key = key;
+ }
+
+ public override bool Equals(object obj)
+ {
+ // NOTE: This takes into consideration that value
+ // types cannot be null.
+ if (key == null && obj == null)
+ {
+ return true;
+ }
+
+ if (!(obj is FakeKey<T>))
+ {
+ return false;
+ }
+
+ return key.Equals(((FakeKey<T>)obj).key);
+ }
+
+ public override int GetHashCode()
+ {
+ // NOTE: This takes into consideration that value
+ // types cannot be null.
+ if (key == null)
+ {
+ return 0; // Emulates Objects.hashcode(object) in Java
+ }
+
+ return key.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ // NOTE: This takes into consideration that value
+ // types cannot be null.
+ if (key == null)
+ {
+ return "null"; // Emulates String.valueOf(object) in Java
+ }
+
+ return key.ToString();
+ }
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestInsertionOrderNullFirst()
+ {
+ var dict = GetNewHashMap<FakeKey<int>, string>();
+
+ dict[null] = "NullValue";
+ dict[new FakeKey<int>(2)] = "MyString";
+ dict[new FakeKey<int>(0)] = "OtherString";
+ dict[new FakeKey<int>(5)] = "NumberFive";
+ dict[new FakeKey<int>(int.MaxValue)] = "Maximum";
+
+ var expectedOrder = new List<KeyValuePair<FakeKey<int>, string>>
+ {
+ new KeyValuePair<FakeKey<int>, string>(null, "NullValue"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(2), "MyString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(0), "OtherString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(5), "NumberFive"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MaxValue), "Maximum"),
+ };
+
+ AssertEnumerationOrder(expectedOrder, dict);
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestInsertionOrderNullInMiddle()
+ {
+ var dict = GetNewHashMap<FakeKey<int>, string>();
+
+ dict[new FakeKey<int>(2)] = "MyString";
+ dict[new FakeKey<int>(0)] = "OtherString";
+ dict[null] = "NullValue";
+ dict[new FakeKey<int>(5)] = "NumberFive";
+ dict[new FakeKey<int>(int.MaxValue)] = "Maximum";
+
+ var expectedOrder = new List<KeyValuePair<FakeKey<int>, string>>
+ {
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(2), "MyString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(0), "OtherString"),
+ new KeyValuePair<FakeKey<int>, string>(null, "NullValue"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(5), "NumberFive"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MaxValue), "Maximum"),
+ };
+
+ AssertEnumerationOrder(expectedOrder, dict);
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestInsertionOrderNullLast()
+ {
+ var dict = GetNewHashMap<FakeKey<int>, string>();
+
+ dict[new FakeKey<int>(2)] = "MyString";
+ dict[new FakeKey<int>(0)] = "OtherString";
+ dict[new FakeKey<int>(5)] = "NumberFive";
+ dict[new FakeKey<int>(int.MaxValue)] = "Maximum";
+ dict[null] = "NullValue";
+
+ var expectedOrder = new List<KeyValuePair<FakeKey<int>, string>>
+ {
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(2), "MyString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(0), "OtherString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(5), "NumberFive"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MaxValue), "Maximum"),
+ new KeyValuePair<FakeKey<int>, string>(null, "NullValue"),
+ };
+
+ AssertEnumerationOrder(expectedOrder, dict);
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestInsertionOrderNullAfterRemovingElements()
+ {
+ var dict = GetDefaultHashMap2();
+
+ // Remove elements before the null value to make sure
+ // we track the proper position of the null
+ dict.Remove(new FakeKey<int>(5));
+ dict.Remove(new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(0), "OtherString"));
+
+ var expectedOrder = new List<KeyValuePair<FakeKey<int>, string>>
+ {
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(2), "MyString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MaxValue), "Maximum"),
+ new KeyValuePair<FakeKey<int>, string>(null, "NullValue"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MinValue), "Minimum"),
+ };
+
+ AssertEnumerationOrder(expectedOrder, dict);
+ }
+
+
+ [Test, LuceneNetSpecific]
+ public void TestInsertionOrderNullAfterRefillingBuckets()
+ {
+ var dict = GetDefaultHashMap2();
+
+ // Remove elements before the null value to make sure
+ // we track the proper position of the null
+ dict.Remove(new FakeKey<int>(5));
+ dict.Remove(new FakeKey<int>(0));
+
+ // This has been verified that it puts the reused key before "new FakeKey<int>(int.MaxValue)"
+ // in a standard Dictionary (putting it out of insertion order)
+ dict.Add(new FakeKey<int>(5), "Testing");
+
+ var expectedOrder = new List<KeyValuePair<FakeKey<int>, string>>
+ {
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(2), "MyString"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MaxValue), "Maximum"),
+ new KeyValuePair<FakeKey<int>, string>(null, "NullValue"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(int.MinValue), "Minimum"),
+ new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(5), "Testing"),
+ };
+
+ AssertEnumerationOrder(expectedOrder, dict);
+ }
+
+ private void AssertEnumerationOrder<TKey, TValue>(IList<KeyValuePair<TKey, TValue>> expectedOrder, IDictionary<TKey, TValue> actualOrder)
+ {
+ // check element order
+ int expectedCount = expectedOrder.Count;
+ var elementEnumerator = actualOrder.GetEnumerator();
+ for (int i = 0; i < expectedCount; i++)
+ {
+ Assert.IsTrue(elementEnumerator.MoveNext());
+ Assert.AreEqual(expectedOrder[i].Key, elementEnumerator.Current.Key);
+ Assert.AreEqual(expectedOrder[i].Value, elementEnumerator.Current.Value);
+ }
+
+ Assert.IsFalse(elementEnumerator.MoveNext());
+ Assert.IsFalse(elementEnumerator.MoveNext());
+
+ // check key order
+ var keyEnumerator = actualOrder.Keys.GetEnumerator();
+ for (int i = 0; i < expectedCount; i++)
+ {
+ Assert.IsTrue(keyEnumerator.MoveNext());
+ Assert.AreEqual(expectedOrder[i].Key, keyEnumerator.Current);
+ }
+
+ Assert.IsFalse(keyEnumerator.MoveNext());
+ Assert.IsFalse(keyEnumerator.MoveNext());
+
+ // check value order
+ var valueEnumerator = actualOrder.Values.GetEnumerator();
+ for (int i = 0; i < expectedCount; i++)
+ {
+ Assert.IsTrue(valueEnumerator.MoveNext());
+ Assert.AreEqual(expectedOrder[i].Value, valueEnumerator.Current);
+ }
+
+ Assert.IsFalse(valueEnumerator.MoveNext());
+ Assert.IsFalse(valueEnumerator.MoveNext());
+ }
+
+
+ [Test, LuceneNetSpecific]
+ public void TestCopyTo()
+ {
+ var dict = GetDefaultHashMap2();
+
+ KeyValuePair<FakeKey<int>, string>[] elements = new KeyValuePair<FakeKey<int>, string>[dict.Count];
+
+ dict.CopyTo(elements, 0);
+
+ // element insertion order
+ var enumerator = elements.GetEnumerator();
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(2), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("MyString", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(0), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("OtherString", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(5), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("NumberFive", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(int.MaxValue), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("Maximum", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(null, ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("NullValue", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(int.MinValue), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("Minimum", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsFalse(enumerator.MoveNext());
+ Assert.IsFalse(enumerator.MoveNext());
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestCopyToWithOffset()
+ {
+ int offset = 5;
+ var dict = GetDefaultHashMap2();
+
+ KeyValuePair<FakeKey<int>, string>[] elements = new KeyValuePair<FakeKey<int>, string>[dict.Count + offset];
+
+ dict.CopyTo(elements, offset);
+
+ // element insertion order
+ var enumerator = elements.GetEnumerator();
+
+ for (int i = 0; i < offset; i++)
+ {
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(null, ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual(null, ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+ }
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(2), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("MyString", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(0), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("OtherString", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(5), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("NumberFive", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(int.MaxValue), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("Maximum", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(null, ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("NullValue", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(new FakeKey<int>(int.MinValue), ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Key);
+ Assert.AreEqual("Minimum", ((KeyValuePair<FakeKey<int>, string>)enumerator.Current).Value);
+
+ Assert.IsFalse(enumerator.MoveNext());
+ Assert.IsFalse(enumerator.MoveNext());
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TestContainsKeyValuePair()
+ {
+ var dict = GetDefaultHashMap2();
+
+ var realTarget = new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(5), "NumberFive");
+ Assert.IsTrue(dict.Contains(realTarget));
+
+ var nullTarget = new KeyValuePair<FakeKey<int>, string>(null, "NullValue");
+ Assert.IsTrue(dict.Contains(nullTarget));
+
+ var invalidTarget = new KeyValuePair<FakeKey<int>, string>(new FakeKey<int>(543), "NullValue");
+ Assert.IsFalse(dict.Contains(invalidTarget));
+
+ dict.Remove(nullTarget);
+ Assert.IsFalse(dict.Contains(nullTarget));
+ }
+ }
+}