lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mhern...@apache.org
Subject [1/9] git commit: adding weakidentitymap with tests.
Date Wed, 20 Aug 2014 02:32:05 GMT
Repository: lucenenet
Updated Branches:
  refs/heads/pcl 7cfd98d54 -> b1d556579


adding weakidentitymap with tests.


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/cb748dd5
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/cb748dd5
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/cb748dd5

Branch: refs/heads/pcl
Commit: cb748dd542ae5292653c279d3dca80033d0b484e
Parents: 7cfd98d
Author: Michael Herndon <mherndon@michaelherndon.com>
Authored: Fri Aug 15 22:26:06 2014 -0400
Committer: Michael Herndon <mherndon@michaelherndon.com>
Committed: Fri Aug 15 22:26:06 2014 -0400

----------------------------------------------------------------------
 Lucene.vs2013.sln.GhostDoc.xml                  |  36 +++
 src/Lucene.Net.Core/Lucene.Net.Core.csproj      |   2 +
 .../Support/AtomicReferenceArray.cs             | 144 +++++++++
 src/Lucene.Net.Core/Util/Constants.cs           |  11 +-
 src/Lucene.Net.Core/Util/RamUsageEstimator.cs   |   8 +-
 src/Lucene.Net.Core/Util/SystemProps.cs         |   2 +-
 src/Lucene.Net.Core/Util/WeakIdentityMap.cs     | 261 ++++++++++++++++
 .../Lucene.Net.Core.Tests.csproj                |   4 +
 .../Lucene.Net.Core.Tests/Util/TestConstants.cs |   4 +-
 .../Util/TestWeakIdentityMap.cs                 | 312 +++++++++++++++++++
 .../Random/RandomExtensions.cs                  |   5 +
 .../Util/LuceneTestCase.cs                      | 142 ++++++++-
 .../Util/RamUsageTester.cs                      |  53 ++--
 13 files changed, 933 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/Lucene.vs2013.sln.GhostDoc.xml
----------------------------------------------------------------------
diff --git a/Lucene.vs2013.sln.GhostDoc.xml b/Lucene.vs2013.sln.GhostDoc.xml
new file mode 100644
index 0000000..24fd3f6
--- /dev/null
+++ b/Lucene.vs2013.sln.GhostDoc.xml
@@ -0,0 +1,36 @@
+<GhostDoc>
+  <SpellChecker>
+    <IncludeExtensions>
+    </IncludeExtensions>
+    <IgnoreExtensions>
+    </IgnoreExtensions>
+    <IgnoreFiles>
+    </IgnoreFiles>
+  </SpellChecker>
+<HelpConfigurations selected="HelpFile">
+  <HelpConfiguration name="HelpFile">
+    <OutputPath>.\Help</OutputPath>
+    <HelpFileName>Lucene.vs2013</HelpFileName>
+    <ImageFolderPath />
+    <HtmlFormats>
+      <HtmlHelp>true</HtmlHelp>
+      <MSHelpViewer>false</MSHelpViewer>
+      <MSHelp2>false</MSHelp2>
+      <Website>false</Website>
+    </HtmlFormats>
+    <IncludeScopes>
+      <Public>true</Public>
+      <Internal>false</Internal>
+      <Protected>false</Protected>
+      <Private>false</Private>
+      <Inherited>true</Inherited>
+      <EnableTags>false</EnableTags>
+      <TagList />
+    </IncludeScopes>
+    <ResolveCrefLinks>true</ResolveCrefLinks>
+    <HeaderText />
+    <FooterText />
+    <SelectedProjects />
+  </HelpConfiguration>
+</HelpConfigurations>
+</GhostDoc>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Lucene.Net.Core.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Lucene.Net.Core.csproj b/src/Lucene.Net.Core/Lucene.Net.Core.csproj
index 75c8337..0d2e02a 100644
--- a/src/Lucene.Net.Core/Lucene.Net.Core.csproj
+++ b/src/Lucene.Net.Core/Lucene.Net.Core.csproj
@@ -58,6 +58,7 @@
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Check.cs" />
+    <Compile Include="Support\AtomicReferenceArray.cs" />
     <Compile Include="Support\DeepCloneNotSupportedException.cs" />
     <Compile Include="Support\EnumUtil.cs" />
     <Compile Include="Support\HashMap.cs" />
@@ -88,6 +89,7 @@
     <Compile Include="Util\SystemProps.cs" />
     <Compile Include="Util\UnicodeUtil.cs" />
     <Compile Include="Util\Version.cs" />
+    <Compile Include="Util\WeakIdentityMap.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Support/AtomicReferenceArray.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Support/AtomicReferenceArray.cs b/src/Lucene.Net.Core/Support/AtomicReferenceArray.cs
new file mode 100644
index 0000000..519a038
--- /dev/null
+++ b/src/Lucene.Net.Core/Support/AtomicReferenceArray.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.Support
+{
+    /// <summary>
+    /// Class AtomicReferenceArray.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public class AtomicReferenceArray<T>
+    {
+        // ReSharper disable once StaticFieldInGenericType
+        private static readonly object SyncLock = new object();
+        private readonly T[] array;
+
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AtomicReferenceArray{T}"/> class.
+        /// </summary>
+        /// <param name="array">The array.</param>
+        public AtomicReferenceArray(T[] array)
+        {
+            Check.NotNull("array", array);
+            
+            int length = array.Length,
+                i = 0;
+
+            this.array = new T[length];
+
+            if (length <= 0) 
+                return;
+
+            for (; i < length; i++)
+                this.Set(i, array[i]);
+        }
+
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AtomicReferenceArray{T}"/> class.
+        /// </summary>
+        /// <param name="capacity">The capacity.</param>
+        public AtomicReferenceArray(int capacity)
+        {
+            this.array = new T[capacity];
+        }
+
+
+        /// <summary>
+        /// Gets or sets the <see cref="T"/> at the specified index.
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <returns>T.</returns>
+        public T this[int index]
+        {
+            get { return this.Get(index); }
+            set { this.Set(index, value);}
+        }
+
+        public int Length
+        {
+            get { return this.array.Length; }
+        }
+
+        /// <summary>
+        /// Compares the value at the specified index with the expected index and sets
+        /// the value if the values are equal.
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <param name="expected">The expected value.</param>
+        /// <param name="value">The update value.</param>
+        /// <returns><c>true</c> if the index was updated, <c>false</c> otherwise.</returns>
+        public bool CompareAndSet(int index, T expected, T value)
+        {
+            lock (SyncLock)
+            {
+                var currentValue = this.array[index];
+                if (!expected.Equals(currentValue)) 
+                    return false;
+                
+                this.array[index] = currentValue;
+                return true;
+            }
+        }
+
+
+        /// <summary>
+        /// Gets the value at the specified index.
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <returns>T.</returns>
+        /// <exception cref="System.IndexOutOfRangeException">
+        /// Thrown when <paramref name="index"/> is less than 0 or greater than or equal to <see cref="Length"/>.
+        /// </exception>
+        private T Get(int index)
+        {
+            //Check.InRangeOfLength(0, this.Length, index);
+
+            return this.array[index];
+        }
+
+
+        /// <summary>
+        /// Gets the old value from the specified index, updates the value, and returns
+        /// the old value.
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <param name="value">The new value at the index.</param>
+        /// <returns>The old <typeparam name="T" /> value.</returns>
+        public T GetAndSet(int index, T value)
+        {
+            //Check.InRangeOfLength(0, this.Length, index);
+
+            lock (SyncLock)
+            {
+                var currentValue = this.array[index];
+                this.array[index] = value;
+
+                return currentValue;
+            }
+        }
+
+        /// <summary>
+        /// Sets the value at the specified index.
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <param name="value">The value.</param>
+        /// <exception cref="System.IndexOutOfRangeException">
+        /// Thrown when <paramref name="index"/> is less than 0 or greater than or equal to <see cref="Length"/>.
+        /// </exception>
+        private void Set(int index, T value)
+        {
+          
+
+            lock (SyncLock)
+            {
+                array[index] = value;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Util/Constants.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/Constants.cs b/src/Lucene.Net.Core/Util/Constants.cs
index 22df3ef..4d1e261 100644
--- a/src/Lucene.Net.Core/Util/Constants.cs
+++ b/src/Lucene.Net.Core/Util/Constants.cs
@@ -24,7 +24,7 @@ namespace Lucene.Net.Util
     /// Global constants that Lucene.Net uses to make decisions based upon the environment
     /// that Lucene.Net is executing on.
     /// </summary>
-    public class Constants
+    public static class Constants
     {
         static Constants()
         {
@@ -55,6 +55,7 @@ namespace Lucene.Net.Util
         /// Determines if the KRE is 32 or 64 bit. 
         /// </summary>
         /// <remarks><para>JRE_IS_64BIT</para></remarks>
+        // ReSharper disable once InconsistentNaming
         public static readonly bool KRE_IS_64BIT = IntPtr.Size == 8;
 
         /// <summary>
@@ -65,7 +66,7 @@ namespace Lucene.Net.Util
         /// <summary>
         /// Gets the name of the operating system.
         /// </summary>
-        public static readonly string OS_NAME = SystemProps.Get("OS");
+        public static readonly string OS_NAME = SystemProps.Get("OS", "UNSUPPORTED");
 
         /// <summary>Returns true, if running on Linux. </summary>
         public static readonly bool LINUX = OS_NAME.StartsWith("Linux");
@@ -79,12 +80,14 @@ namespace Lucene.Net.Util
         /// <summary>
         /// Gets the proccess architechture for the current machine.
         /// </summary>
-        public static string OS_ARCH = SystemProps.Get("PROCESSOR_ARCHITECTURE");
+        // ReSharper disable once InconsistentNaming
+        public static string OS_ARCH = SystemProps.Get("PROCESSOR_ARCHITECTURE", "x86");
 
 
         /// <summary>
         /// Gets the version of the operating system for the current machine.
         /// </summary>
+        // ReSharper disable once InconsistentNaming
         public static string OS_VERSION = SystemProps.Get("OS_VERSION", "?");
 
 
@@ -102,11 +105,13 @@ namespace Lucene.Net.Util
         ///         using indexes created with ALPHA/BETA versions with the released version.
         ///     </para>
         /// </remarks>
+        // ReSharper disable once InconsistentNaming
         public static readonly System.String LUCENE_MAIN_VERSION = Ident("5.0");
 
         /// <summary>
         /// This is the Lucene version for display purposes.
         /// </summary>
+        // ReSharper disable once InconsistentNaming
         public static System.String LUCENE_VERSION;
 
         // this method prevents inlining the final version constant in compiled

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Util/RamUsageEstimator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/RamUsageEstimator.cs b/src/Lucene.Net.Core/Util/RamUsageEstimator.cs
index 83f4914..0e50820 100644
--- a/src/Lucene.Net.Core/Util/RamUsageEstimator.cs
+++ b/src/Lucene.Net.Core/Util/RamUsageEstimator.cs
@@ -61,7 +61,7 @@ namespace Lucene.Net.Util
     /// </remarks>
     // The JVM FEATURE enum should only be ported if mono or different version of the 
     // .NET framework handle memory allocation differently.
-    public sealed class RamUsageEstimator
+    public static class RamUsageEstimator
     {
         /// <summary>
         /// The number of bytes for one killabyte. 
@@ -169,12 +169,6 @@ namespace Lucene.Net.Util
         public static readonly int NUM_BYTES_OBJECT_ALIGNMENT;
 
 
-        /// <summary>
-        /// No instantiation
-        /// </summary>
-        private RamUsageEstimator()
-        {
-        }
 
 
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Util/SystemProps.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/SystemProps.cs b/src/Lucene.Net.Core/Util/SystemProps.cs
index 4f8338b..1e0ca92 100644
--- a/src/Lucene.Net.Core/Util/SystemProps.cs
+++ b/src/Lucene.Net.Core/Util/SystemProps.cs
@@ -64,7 +64,7 @@ namespace Lucene.Net.Util
         /// <returns>The <typeparamref name="T"/> value.</returns>
         public static T Get<T>(string key)
         {
-            return Get<T>(key, default(T));
+            return Get(key, default(T));
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/WeakIdentityMap.cs b/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
new file mode 100644
index 0000000..f3916aa
--- /dev/null
+++ b/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
@@ -0,0 +1,261 @@
+/*
+* 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.
+*/
+
+using System.Linq;
+
+namespace Lucene.Net.Util
+{
+    using Lucene.Net.Support;
+    using System;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Runtime.CompilerServices;
+
+
+
+    /// <summary>
+    /// Class WeakIdentityMap. This class cannot be inherited.
+    /// </summary>
+    /// <typeparam name="TKey">The type of the t key.</typeparam>
+    /// <typeparam name="TValue">The type of the t value.</typeparam>
+    public sealed class WeakIdentityMap<TKey, TValue>
+        where TKey : class
+    {
+       
+        // we keep a hard reference to our NULL key, so map supports null keys that never get GCed:
+        // ReSharper disable once StaticFieldInGenericType
+        public static readonly object NULL_VALUE = new object();
+
+        //private readonly ReferenceQueue<object> queue = new ReferenceQueue<object>();
+        private readonly  IDictionary<IdentityWeakReference, TValue> backingStore;
+
+        private readonly bool reapOnReadEnabled;
+
+        /// <summary>
+        /// Initializes a new instance of <see cref="WeakIdentityMap{TKey, TValue}"/>
+        /// </summary>
+        /// <param name="backingStore">The backing store.</param>
+        /// <param name="reapOnRead">if set to <c>true</c> [reap on read].</param>
+        private WeakIdentityMap(IDictionary<IdentityWeakReference, TValue> backingStore, bool reapOnRead)
+        {
+            this.backingStore = backingStore;
+            this.reapOnReadEnabled = reapOnRead;
+        }
+
+        /// <summary>
+        /// Returns the number of key-value mappings in this map. this result is a snapshot,
+        /// and may not reflect unprocessed entries that will be removed before next
+        /// attempted access because they are no longer referenced.
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                if (this.backingStore.Count == 0)
+                {
+                    return 0;
+                }
+                this.ReapOnRead();
+                return this.backingStore.Count;
+            }
+        }
+
+        /// <summary>
+        /// Returns <c>True</c> when this map contains no key-value mappings. </summary>
+        public bool Empty
+        {
+            get
+            {
+                return this.Count == 0;
+            }
+        }
+
+        public IEnumerable<TKey> Keys
+        {
+            // .NET port: using this method which mimics IDictionary instead of KeyIterator()
+            get
+            {
+                foreach (var key in backingStore.Keys)
+                {
+                    var target = key.Target;
+
+                    if (target == null)
+                        continue;
+                    
+                    if (Object.ReferenceEquals(target, NULL_VALUE))
+                        yield return null;
+                    else
+                        yield return (TKey)target;
+                }
+            }
+        }
+
+        public IEnumerable<TValue> Values
+        {
+            get
+            {
+                this.ReapOnRead();
+                return this.backingStore.Values;
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new <see cref="WeakIdentityMap{TKey,TValue}"/> based on a <seealso cref="ConcurrentHashMap"/>.
+        /// The map <a href="#reapInfo">cleans up the reference queue on every read operation</a>.
+        /// </summary>
+        public static WeakIdentityMap<TKey, TValue> NewConcurrentHashMap()
+        {
+            return NewConcurrentHashMap(true);
+        }
+
+        /// <summary>
+        /// Creates a new {@code WeakIdentityMap} based on a <seealso cref="ConcurrentHashMap"/>. </summary>
+        /// <param name="reapOnRead"> controls if the map <a href="#reapInfo">cleans up the reference queue on every read operation</a>. </param>
+        public static WeakIdentityMap<TKey, TValue> NewConcurrentHashMap(bool reapOnRead)
+        {
+            return new WeakIdentityMap<TKey, TValue>(new ConcurrentDictionary<IdentityWeakReference, TValue>(), reapOnRead);
+        }
+
+        /// <summary>
+        /// Creates a new {@code WeakIdentityMap} based on a non-synchronized <seealso cref="HashMap"/>.
+        /// The map <a href="#reapInfo">cleans up the reference queue on every read operation</a>.
+        /// </summary>
+        public static WeakIdentityMap<TKey, TValue> NewHashMap()
+        {
+            return NewHashMap(false);
+        }
+
+        /// <summary>
+        /// Creates a new {@code WeakIdentityMap} based on a non-synchronized <seealso cref="HashMap"/>. </summary>
+        /// <param name="reapOnRead"> controls if the map <a href="#reapInfo">cleans up the reference queue on every read operation</a>. </param>
+        public static WeakIdentityMap<TKey, TValue> NewHashMap(bool reapOnRead)
+        {
+            return new WeakIdentityMap<TKey, TValue>(new HashMap<IdentityWeakReference, TValue>(), reapOnRead);
+        }
+        /// <summary>
+        /// Removes all of the mappings from this map. 
+        /// </summary>
+        public void Clear()
+        {
+            this.backingStore.Clear();
+            this.Reap();
+        }
+
+        /// <summary>
+        /// Returns <c>True</c> if this map contains a mapping for the specified key, otherwise <c>False</c>.
+        /// </summary>
+        public bool ContainsKey(object key)
+        {
+            this.ReapOnRead();
+            return backingStore.ContainsKey(new IdentityWeakReference(key));
+        }
+
+        /// <summary>
+        /// Returns the value to which the specified key is mapped. 
+        /// </summary>
+        public TValue Get(object key)
+        {
+            TValue value;
+            
+            this.ReapOnRead();
+            // Java's collections return null. TryGetValue must be used.
+            this.backingStore.TryGetValue(new IdentityWeakReference(key), out value);
+            
+            return value;
+        }
+
+        
+        public TValue Put(TKey key, TValue value)
+        {
+            this.Reap();
+            return this.backingStore[new IdentityWeakReference(key)] = value;
+        }
+        /// <summary>
+        /// this method manually cleans up the reference queue to remove all garbage
+        /// collected key/value pairs from the map.  
+        /// </summary>
+        public void Reap()
+        {
+            lock (backingStore)
+            {
+                var keysToRemove = backingStore.Keys.Where(o => !o.IsAlive).ToList();
+
+                foreach (var key in keysToRemove)
+                {
+                    backingStore.Remove(key);
+                }
+            }
+        }
+
+        private void ReapOnRead()
+        {
+            if(this.reapOnReadEnabled)
+                this.Reap();
+        }
+
+        /// <summary>
+        /// Removes the mapping for a key from this weak hash map if it is present.
+        /// Returns the value to which this map previously associated the key,
+        /// or {@code null} if the map contained no mapping for the key.
+        /// A return value of {@code null} does not necessarily indicate that
+        /// the map contained.
+        /// </summary>
+        public bool Remove(object key)
+        {
+            this.Reap();
+            return backingStore.Remove(new IdentityWeakReference(key));
+        }
+
+   
+
+
+        private sealed class IdentityWeakReference : WeakReference
+        {
+            private readonly int hash;
+
+            internal IdentityWeakReference(object obj/*, ReferenceQueue<object> queue*/)
+                : base(obj ?? NULL_VALUE/*, queue*/)
+            {
+               
+
+                hash = RuntimeHelpers.GetHashCode(obj);
+            }
+
+            public override bool Equals(object obj)
+            {
+                if (this == obj)
+                {
+                    return true;
+                }
+                if (obj is IdentityWeakReference)
+                {
+                    var reference = (IdentityWeakReference)obj;
+                    if (this.Target == reference.Target)
+                    {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            public override int GetHashCode()
+            {
+                return hash;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.Core.Tests/Lucene.Net.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.Core.Tests/Lucene.Net.Core.Tests.csproj b/test/Lucene.Net.Core.Tests/Lucene.Net.Core.Tests.csproj
index 8f6632f..5ed7234 100644
--- a/test/Lucene.Net.Core.Tests/Lucene.Net.Core.Tests.csproj
+++ b/test/Lucene.Net.Core.Tests/Lucene.Net.Core.Tests.csproj
@@ -70,6 +70,7 @@
     <Compile Include="Util\TestRamEstimatorUsage.cs" />
     <Compile Include="Util\TestSetOnce.cs" />
     <Compile Include="Util\TestVersion.cs" />
+    <Compile Include="Util\TestWeakIdentityMap.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="xunit.abstractions">
@@ -95,6 +96,9 @@
       <Name>Lucene.Net.TestFramework</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.Core.Tests/Util/TestConstants.cs
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.Core.Tests/Util/TestConstants.cs b/test/Lucene.Net.Core.Tests/Util/TestConstants.cs
index c93f42e..2c4ee01 100644
--- a/test/Lucene.Net.Core.Tests/Util/TestConstants.cs
+++ b/test/Lucene.Net.Core.Tests/Util/TestConstants.cs
@@ -65,8 +65,8 @@ namespace Lucene.Net.Util
         public virtual void TestBuildSetup()
         {
             // common-build.xml sets lucene.version, if not, we skip this test!
-            string defaultVersion = "5.0";
-            string version = SystemProps.Get("lucene.version", defaultVersion);
+            const string defaultVersion = "5.0";
+            var version = SystemProps.Get("lucene.version", defaultVersion);
             Ok(version != null);
 
             if (version != "5.0")

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.Core.Tests/Util/TestWeakIdentityMap.cs
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.Core.Tests/Util/TestWeakIdentityMap.cs b/test/Lucene.Net.Core.Tests/Util/TestWeakIdentityMap.cs
new file mode 100644
index 0000000..8c1098f
--- /dev/null
+++ b/test/Lucene.Net.Core.Tests/Util/TestWeakIdentityMap.cs
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+namespace Lucene.Net.Util
+{
+    using Random;
+    using Support;
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Threading.Tasks;
+
+ 
+    public class TestWeakIdentityMap : LuceneTestCase
+    {
+
+        [Test]
+        public async virtual void TestSimpleHashMap()
+        {
+            var map = WeakIdentityMap<string, string>.NewHashMap(this.Random.NextBoolean());
+            // we keep strong references to the keys,
+            // so WeakIdentityMap will not forget about them:
+            string key1 = "foo",
+                key2 = "foo",
+                key3 = "foo",
+                key4 = null;
+
+
+
+            // Java Version assumes that the 3 keys
+            // are not the same instance.  In .NET all 3 keys will 
+            // be considered the same reference.
+           
+            Equal(key1, key2);
+            Equal(key1, key3);
+            Equal(key2, key3);
+
+            // try null key & check its iterator also return null:
+// ReSharper disable once ExpressionIsAlwaysNull
+            map.Put(key4, "null");
+            {
+                var iterator = map.Keys.GetEnumerator();
+                Ok(iterator.MoveNext());
+                Null(iterator.Current);
+                Ok(!iterator.MoveNext());
+                Ok(!iterator.MoveNext());
+            }
+            // 2 more keys:
+            map.Put(key1, "bar1");
+            map.Put(key2, "bar2");
+
+            Equal(2, map.Count);
+
+            // this will not work in .NET, key1 is the same as key2
+            // Equal("bar1", map.Get(key1));
+            // Equal(null, map.Get(key3));
+            Equal("bar2", map.Get(key2));
+            Equal("null", map.Get(null));
+
+            Ok(map.ContainsKey(key1));
+            Ok(map.ContainsKey(key2));
+            Ok(map.ContainsKey(key3));
+            Ok(map.ContainsKey(null));
+
+            // repeat and check that we have no double entries
+            map.Put(key1, "bar1");
+            map.Put(key2, "bar2");
+            map.Put(null, "null");
+
+            Equal(2, map.Count);
+
+            // this will not work in .NET, key1, key2, key3 are the same reference
+            // Equal("bar1", map.Get(key1));
+            // Equal(null, map.Get(key3));
+            Equal("bar2", map.Get(key2));
+        
+            Equal("null", map.Get(null));
+
+            Ok(map.ContainsKey(key1));
+            Ok(map.ContainsKey(key2));
+            Ok(map.ContainsKey(key3));
+            Ok(map.ContainsKey(null));
+
+            map.Remove(null);
+            Equal(1, map.Count);
+            map.Remove(key1);
+            Equal(0, map.Count);
+
+            key1 = "a";
+            key2 = "b";
+            key3 = "c";
+
+            map.Put(key1, "bar1");
+            map.Put(key2, "bar2");
+            map.Put(key3, "bar1");
+
+            int c = 0, keysAssigned = 0;
+            for (var iterator = map.Keys.GetEnumerator(); iterator.MoveNext(); )
+            {
+               
+                var k = iterator.Current;
+                Ok(k == key1 || k == key2 || k == key3);
+                keysAssigned += (k == key1) ? 1 : ((k == key2) ? 2 : 4);
+                c++;
+            }
+            Equal(3, c);
+            Equal(1 + 2 + 4, keysAssigned, "all keys must have been seen");
+
+            c = 0;
+            for (var iterator = map.Values.GetEnumerator(); iterator.MoveNext(); )
+            {
+                var v = iterator.Current;
+                Ok(v.StartsWith("bar"));
+                c++;
+            }
+            Equal(3, c);
+
+            // clear strong refs
+            // ReSharper disable RedundantAssignment
+            key1 = null;
+            key2 = null;
+            key3 = null;
+
+            // check that GC does not cause problems in reap() method, wait 1 second and let GC work:
+            var size = map.Count;
+            for (var i = 0; size > 0 && i < 10; i++)
+            {
+               
+                GC.Collect();
+                var newSize = map.Count;
+                Ok(size >= newSize, "previousSize(" + size + ")>=newSize(" + newSize + ")");
+                size = newSize;
+                    
+                await Task.Delay(new TimeSpan(100L));
+                c = 0;
+                for (var iteration = map.Keys.GetEnumerator(); iteration.MoveNext(); )
+                {
+                    NotNull(iteration.Current);
+                    c++;
+                }
+                newSize = map.Count;
+                Ok(size >= c, "previousSize(" + size + ")>=iteratorSize(" + c + ")");
+                Ok(c >= newSize, "iteratorSize(" + c + ")>=newSize(" + newSize + ")");
+                size = newSize;
+            }
+
+            map.Clear();
+            Equal(0, map.Count);
+            Ok(map.Empty);
+
+            IEnumerator<string> it = map.Keys.GetEnumerator();
+            Ok(!it.MoveNext());
+            /*try
+            {
+              it.Next();
+              Assert.Fail("Should throw NoSuchElementException");
+            }
+            catch (NoSuchElementException nse)
+            {
+            }*/
+
+            key1 = "foo1";
+            key2 = "foo2";
+            map.Put(key1, "bar1");
+            map.Put(key2, "bar2");
+            Equal(2, map.Count);
+
+            map.Clear();
+            Equal(0, map.Count);
+            Ok(map.Empty);
+        }
+
+        [Test]
+        public async virtual void TestConcurrentHashMap()
+        {
+            // don't make threadCount and keyCount random, otherwise easily OOMs or fails otherwise:
+            const int threadCount = 8, keyCount = 1024;
+            var tasks = new List<Task>();
+            var map = WeakIdentityMap<object, int?>.NewConcurrentHashMap(this.Random.NextBoolean());
+            // we keep strong references to the keys,
+            // so WeakIdentityMap will not forget about them:
+            var keys = new AtomicReferenceArray<object>(keyCount);
+            for (var j = 0; j < keyCount; j++)
+            {
+                keys[j] = new object();
+            }
+
+            for (var t = 0; t < threadCount; t++)
+            {
+                var rnd = new Random(this.Random.Next());
+                tasks.Add(Task.Run(() =>
+                {
+                       
+                    var helper = new RunnableAnonymousInnerClassHelper(this, keyCount, map, keys, rnd);
+                    helper.Run();
+                          
+                      
+                       
+                }));
+            }
+            await Task.WhenAll(tasks);
+
+            var taskWithException = tasks.FirstOrDefault(o => o.Exception != null);
+            if (taskWithException != null)
+                throw taskWithException.Exception;
+            
+
+            // clear strong refs
+            for (var j = 0; j < keyCount; j++)
+            {
+                keys[j] = null;
+            }
+
+            // check that GC does not cause problems in reap() method:
+            var size = map.Count;
+            for (var i = 0; size > 0 && i < 10; i++)
+            {
+
+                GC.Collect();
+                int newSize = map.Count,
+                    c = 0;
+
+                Ok(size >= newSize, "previousSize(" + size + ")>=newSize(" + newSize + ")");
+                size = newSize;
+                await Task.Delay(100);
+
+                for (var iterator = map.Keys.GetEnumerator(); iterator.MoveNext(); )
+                {
+                    NotNull(iterator.Current);
+                    c++;
+                }
+                newSize = map.Count;
+                Ok(size >= c, "previousSize(" + size + ")>=iteratorSize(" + c + ")");
+                Ok(c >= newSize, "iteratorSize(" + c + ")>=newSize(" + newSize + ")");
+                size = newSize;
+            }
+        }
+
+        private class RunnableAnonymousInnerClassHelper 
+        {
+            private readonly TestWeakIdentityMap outerInstance;
+
+            private readonly int keyCount;
+            private readonly WeakIdentityMap<object, int?> map;
+            private readonly AtomicReferenceArray<object> keys;
+            private readonly Random rnd;
+
+
+            public RunnableAnonymousInnerClassHelper(TestWeakIdentityMap outerInstance, int keyCount, WeakIdentityMap<object, int?> map, AtomicReferenceArray<object> keys, Random rnd)
+            {
+                this.outerInstance = outerInstance;
+                this.keyCount = keyCount;
+                this.map = map;
+                this.keys = keys;
+                this.rnd = rnd;
+            }
+
+            public void Run()
+            {
+// ReSharper disable once InvokeAsExtensionMethod
+                var count =  this.outerInstance.AtLeast(10000);
+                for (var i = 0; i < count; i++)
+                {
+                    var j = rnd.Next(keyCount);
+                    switch (rnd.Next(5))
+                    {
+                        case 0:
+                            map.Put(keys[j], Convert.ToInt32(j));
+                            break;
+                        case 1:
+                            var v = map.Get(keys[j]);
+                            if (v != null)
+                            {
+                                Equal(j, (int)v);
+                            }
+                            break;
+                        case 2:
+                            map.Remove(keys[j]);
+                            break;
+                        case 3:
+                            // renew key, the old one will be GCed at some time:
+                            keys[j] = new object();
+                            break;
+                        case 4:
+                            // check iterator still working
+                            for (var it = map.Keys.GetEnumerator(); it.MoveNext(); )
+                            {
+                                NotNull(it.Current);
+                            }
+                            break;
+                        default:
+                            throw new LuceneAssertionException("This point should not be reached");
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.TestFramework/Random/RandomExtensions.cs
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.TestFramework/Random/RandomExtensions.cs b/test/Lucene.Net.TestFramework/Random/RandomExtensions.cs
index c857372..eb0112f 100644
--- a/test/Lucene.Net.TestFramework/Random/RandomExtensions.cs
+++ b/test/Lucene.Net.TestFramework/Random/RandomExtensions.cs
@@ -67,6 +67,11 @@ namespace Lucene.Net.Random
                 return minValue + (int)Math.Round(random.NextDouble() * range);
         }
 
+        public static bool NextBoolean(this Random random)
+        {
+            return random.NextDouble() < 0.5;
+        }
+
         public static int RandomInt(this Random random, int maxValue)
         {
             if (maxValue == 0)

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.TestFramework/Util/LuceneTestCase.cs b/test/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
index 70e580d..f3428c6 100644
--- a/test/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
+++ b/test/Lucene.Net.TestFramework/Util/LuceneTestCase.cs
@@ -15,8 +15,13 @@
  * limitations under the License.
  */
 
+using System.Runtime.Serialization;
+
 namespace Lucene.Net.Util
 {
+#if PORTABLE || K10
+    using Lucene.Net.Support;
+#endif
     using System;
     using System.Collections.Generic;
     using System.Diagnostics;
@@ -62,6 +67,70 @@ namespace Lucene.Net.Util
 
 #if XUNIT
 
+        [Serializable]
+        public class LuceneAssertionException : Exception
+        {
+            //
+            // For guidelines regarding the creation of new exception types, see
+            //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
+            // and
+            //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
+            //
+
+            public LuceneAssertionException()
+            {
+            }
+
+            public LuceneAssertionException(string message) : base(message)
+            {
+            }
+
+            public LuceneAssertionException(string message, Exception inner) : base(message, inner)
+            {
+            }
+
+#if NET45
+            protected LuceneAssertionException(
+                System.Runtime.Serialization.SerializationInfo info,
+                StreamingContext context) : base(info, context)
+            {
+            }
+#endif
+        }
+
+        [DebuggerHidden]
+        public static void Null(object value, string message = null, params  object[] args)
+        {
+            try
+            {
+                Assert.Null(value);
+            }
+            catch (Exception ex)
+            {
+                var msg = message ?? "The value must be null.";
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
+        }
+
+        public static void NotNull(object value, string message = null, params object[] args)
+        {
+            try
+            {
+                Assert.NotNull(value);
+            }
+            catch (Exception ex)
+            {
+                var msg = message ?? "The value must not be null.";
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
+        }
+
         /// <summary>
         /// Asserts that two object are the same.
         /// </summary>
@@ -85,27 +154,84 @@ namespace Lucene.Net.Util
         }
 
         [DebuggerHidden]
-        public static void Equal(string expected, string actual)
+        public static void Equal(string expected, string actual, string message = null, params object[] args)
         {
-            Assert.Equal(expected, actual);
+            try
+            {
+                Assert.Equal(expected, actual);
+            }
+            catch (Exception ex)
+            {
+                if (message == null)
+                    throw;
+
+                var msg = message;
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
         }
 
         [DebuggerHidden]
-        public static void Equal<T>(T expected, T actual)
+        public static void Equal<T>(T expected, T actual, string message = null, params object[] args)
         {
-            Assert.Equal(expected, actual);
+            try
+            {
+                Assert.Equal(expected, actual);
+            }
+            catch (Exception ex)
+            {
+                if (message == null)
+                    throw;
+
+                var msg = message;
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
         }
 
         [DebuggerHidden]
-        public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual)
+        public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual, string message= null, params object[] args)
         {
-            Assert.Equal(expected, actual);
+            try
+            {
+                Assert.Equal(expected, actual);
+            }
+            catch (Exception ex)
+            {
+                if (message == null)
+                    throw;
+
+                var msg = message;
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
         }
 
         [DebuggerHidden]
-        public static void NotEqual<T>(T expected, T actual)
+        public static void NotEqual<T>(T expected, T actual, string message = null, params object[] args)
         {
-            Assert.NotEqual(expected, actual);
+            try
+            {
+                Assert.NotEqual(expected, actual);
+            }
+            catch (Exception ex)
+            {
+                if (message == null)
+                    throw;
+
+                var msg = message;
+                if (args != null && args.Length > 0)
+                    msg = string.Format(msg, args);
+
+                throw new LuceneAssertionException(msg, ex);
+            }
+           
         }
 
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cb748dd5/test/Lucene.Net.TestFramework/Util/RamUsageTester.cs
----------------------------------------------------------------------
diff --git a/test/Lucene.Net.TestFramework/Util/RamUsageTester.cs b/test/Lucene.Net.TestFramework/Util/RamUsageTester.cs
index d944be0..f26cf2f 100644
--- a/test/Lucene.Net.TestFramework/Util/RamUsageTester.cs
+++ b/test/Lucene.Net.TestFramework/Util/RamUsageTester.cs
@@ -21,10 +21,8 @@ namespace Lucene.Net.Util
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Linq;
-    using System.Text;
     using System.Reflection;
-    using System.Threading.Tasks;
-    using Lucene.Net.Support;
+    using Support;
 
 
     public class RamUsageTester
@@ -56,13 +54,13 @@ namespace Lucene.Net.Util
         private static long MeasureObjectSize(object root, Accumulator accumulator)
         {
             // Objects seen so far.
-            IdentityHashSet<object> seen = new IdentityHashSet<object>();
+            var seen = new IdentityHashSet<object>();
 
             // Class cache with reference Field and precalculated shallow size. 
-            HashMap<Type, ClassCache> classCache = new HashMap<Type, ClassCache>();
+            var classCache = new HashMap<Type, ClassCache>();
             
             // Stack of objects pending traversal. Recursion caused stack overflows. 
-            Stack<object> stack = new Stack<object>();
+            var stack = new Stack<object>();
             stack.Push(root);
 
             long totalSize = 0;
@@ -78,12 +76,11 @@ namespace Lucene.Net.Util
 
                 seen.Add(ob);
 
-                Type type = ob.GetType();
+                var type = ob.GetType();
                 if (type.IsArray)
                 {
                     var array = (Array)ob;
                     var shallowSize = RamUsageEstimator.ShallowSizeOf(ob);
-                    var length = array.Length;
                     var values = new List<object>();
 
                     var elementType = type.GetElementType().GetTypeInfo();
@@ -106,11 +103,7 @@ namespace Lucene.Net.Util
                         classCache.Add(type, cachedInfo = CreateCacheEntry(type));
                     }
 
-                    var fieldValues = new Dictionary<FieldInfo, object>();
-                    foreach (var field in cachedInfo.ReferenceFields)
-                    {
-                        fieldValues.Add(field, field.GetValue(ob));
-                    }
+                    var fieldValues = cachedInfo.ReferenceFields.ToDictionary(field => field, field => field.GetValue(ob));
 
                     totalSize += accumulator.AccumulateObject(ob, cachedInfo.AlignedShallowInstanceSize, fieldValues, stack);
                 }
@@ -134,13 +127,12 @@ namespace Lucene.Net.Util
         /// </summary>
         private static ClassCache CreateCacheEntry(Type instanceType)
         {
-            ClassCache cachedInfo;
             long shallowInstanceSize = RamUsageEstimator.NUM_BYTES_OBJECT_HEADER;
-            List<FieldInfo> referenceFields = new List<FieldInfo>(32);
+            var referenceFields = new List<FieldInfo>(32);
 
             // GetRuntimeFields includes inherited fields. 
             var fields = instanceType.GetRuntimeFields().Where(o => !o.IsStatic);
-            foreach (FieldInfo f in fields)
+            foreach (var f in fields)
             {
                 shallowInstanceSize = RamUsageEstimator.AdjustForField(shallowInstanceSize, f);
 
@@ -151,8 +143,7 @@ namespace Lucene.Net.Util
 
             }
 
-            cachedInfo = new ClassCache(RamUsageEstimator.AlignObjectSize(shallowInstanceSize), referenceFields.ToArray());
-            return cachedInfo;
+            return new ClassCache(RamUsageEstimator.AlignObjectSize(shallowInstanceSize), referenceFields.ToArray());
         }
 
         /// <summary>
@@ -213,7 +204,7 @@ namespace Lucene.Net.Util
         /// 
         /// TODO: If this is useful outside this class, make it public - needs some work
         /// </summary>
-        public sealed class IdentityHashSet<KType> : IEnumerable<KType>
+        public sealed class IdentityHashSet<TKey> : IEnumerable<TKey>
         {
             /// <summary>
             /// Default load factor.
@@ -278,7 +269,7 @@ namespace Lucene.Net.Util
             /// <summary>
             /// Adds a reference to the set. Null keys are not allowed.
             /// </summary>
-            public bool Add(KType e)
+            public bool Add(TKey e)
             {
                 Debug.Assert(e != null, "Null keys not allowed.");
 
@@ -287,8 +278,9 @@ namespace Lucene.Net.Util
                     ExpandAndRehash();
                 }
 
-                int mask = Keys.Length - 1;
-                int slot = Rehash(e) & mask;
+                int mask = Keys.Length - 1,
+                    slot = Rehash(e) & mask;
+                
                 object existing;
                 while ((existing = Keys[slot]) != null)
                 {
@@ -298,6 +290,7 @@ namespace Lucene.Net.Util
                     }
                     slot = (slot + 1) & mask;
                 }
+                
                 Assigned++;
                 Keys[slot] = e;
                 return true;
@@ -306,7 +299,7 @@ namespace Lucene.Net.Util
             /// <summary>
             /// Checks if the set contains a given ref.
             /// </summary>
-            public bool Contains(KType e)
+            public bool Contains(TKey e)
             {
                 int mask = Keys.Length - 1;
                 int slot = Rehash(e) & mask;
@@ -437,7 +430,7 @@ namespace Lucene.Net.Util
                 }
             }
 
-            public IEnumerator<KType> GetEnumerator()
+            public IEnumerator<TKey> GetEnumerator()
             {
                 return new IteratorAnonymousInnerClassHelper(this);
             }
@@ -447,11 +440,11 @@ namespace Lucene.Net.Util
                 return GetEnumerator();
             }
 
-            private class IteratorAnonymousInnerClassHelper : IEnumerator<KType>
+            private class IteratorAnonymousInnerClassHelper : IEnumerator<TKey>
             {
-                private readonly IdentityHashSet<KType> OuterInstance;
+                private readonly IdentityHashSet<TKey> OuterInstance;
 
-                public IteratorAnonymousInnerClassHelper(IdentityHashSet<KType> outerInstance)
+                public IteratorAnonymousInnerClassHelper(IdentityHashSet<TKey> outerInstance)
                 {
                     this.OuterInstance = outerInstance;
                     pos = -1;
@@ -460,7 +453,7 @@ namespace Lucene.Net.Util
 
                 internal int pos;
                 internal object nextElement;
-                internal KType current;
+                internal TKey current;
 
 
                 public bool MoveNext()
@@ -472,11 +465,11 @@ namespace Lucene.Net.Util
                     }
 
                     nextElement = FetchNext();
-                    current = (KType)r;
+                    current = (TKey)r;
                     return true;
                 }
 
-                public KType Current
+                public TKey Current
                 {
                     get { return current; }
                 }


Mime
View raw message