diff --git a/src/ConcurrentCollections.sln b/src/ConcurrentCollections.sln
index 295c310..3f17b1d 100644
--- a/src/ConcurrentCollections.sln
+++ b/src/ConcurrentCollections.sln
@@ -1,9 +1,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.9
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConcurrentHashSet", "ConcurrentHashSet\ConcurrentHashSet.csproj", "{58063048-C7B0-4F4D-B27E-1ED5F9789AF7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConcurrentHashSet", "ConcurrentHashSet\ConcurrentHashSet.csproj", "{58063048-C7B0-4F4D-B27E-1ED5F9789AF7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConcurrentHashSet.Test", "ConcurrentHashSet.Test\ConcurrentHashSet.Test.csproj", "{A559187C-0971-42CD-AE8C-2BC1132965FE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,8 +17,15 @@ Global
{58063048-C7B0-4F4D-B27E-1ED5F9789AF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58063048-C7B0-4F4D-B27E-1ED5F9789AF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58063048-C7B0-4F4D-B27E-1ED5F9789AF7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A559187C-0971-42CD-AE8C-2BC1132965FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A559187C-0971-42CD-AE8C-2BC1132965FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A559187C-0971-42CD-AE8C-2BC1132965FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A559187C-0971-42CD-AE8C-2BC1132965FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F8839D42-C1EB-4D5A-8C15-D7A32C0EA9E2}
+ EndGlobalSection
EndGlobal
diff --git a/src/ConcurrentHashSet.Test/ConcurrentHashSet.Test.csproj b/src/ConcurrentHashSet.Test/ConcurrentHashSet.Test.csproj
new file mode 100644
index 0000000..eec684e
--- /dev/null
+++ b/src/ConcurrentHashSet.Test/ConcurrentHashSet.Test.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/src/ConcurrentHashSet.Test/Program.cs b/src/ConcurrentHashSet.Test/Program.cs
new file mode 100644
index 0000000..65d5f02
--- /dev/null
+++ b/src/ConcurrentHashSet.Test/Program.cs
@@ -0,0 +1,68 @@
+// See https://aka.ms/new-console-template for more information
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Text;
+
+Console.WriteLine("ConcurrentHashSet test now!");
+
+try
+{
+ var watch1 = new Stopwatch();
+ watch1.Start();
+
+ int total1 = 0;
+ ConcurrentHashSet hashSet1 = new ConcurrentHashSet();
+ using (var sr = new StreamReader("stopwords_en_nltk.txt", Encoding.UTF8))
+ {
+ string? line = null;
+ while ((line = sr.ReadLine()) != null)
+ {
+ if(!hashSet1.Contains(line))
+ hashSet1.Add(line);
+ System.Threading.Interlocked.Add(ref total1, 1);
+ }
+ }
+ watch1.Stop();
+ Console.WriteLine($"ConcurrentHashSet: stopwords_en_nltk.txt load finished, Count:{hashSet1.Count}, total:{total1}. time elapsed {watch1.ElapsedMilliseconds} ms");
+
+ var watch2 = new Stopwatch();
+ watch2.Start();
+ int total2 = 0;
+ ConcurrentHashSet hashSet2 = new ConcurrentHashSet();
+ System.Threading.Tasks.Parallel.ForEach(File.ReadLines("stopwords_en_nltk.txt", Encoding.UTF8), (line, _, lineNumber) =>
+ {
+ if (!hashSet2.Contains(line))
+ hashSet2.Add(line);
+ System.Threading.Interlocked.Add(ref total2, 1);
+ });
+
+ watch2.Stop();
+ Console.WriteLine($"ConcurrentHashSet: stopwords_en_nltk.txt load as parallel finished, Count:{hashSet2.Count}, total:{total2}. time elapsed {watch2.ElapsedMilliseconds} ms");
+
+ var watch3 = new Stopwatch();
+ watch3.Start();
+ int total3 = 0;
+ ConcurrentBag bag = new ConcurrentBag();
+ System.Threading.Tasks.Parallel.ForEach(File.ReadLines("stopwords_en_nltk.txt", Encoding.UTF8), (line, _, lineNumber) =>
+ {
+ if (!bag.Contains(line))
+ bag.Add(line);
+ System.Threading.Interlocked.Add(ref total3, 1);
+ });
+
+ watch3.Stop();
+
+ Console.WriteLine($"ConcurrentBag: stopwords_en_nltk.txt load as parallel finished, Count:{bag.Count}, total:{total3}. time elapsed {watch3.ElapsedMilliseconds} ms");
+
+ Console.WriteLine("Press any key to exit.");
+}
+catch (IOException e)
+{
+ Console.WriteLine(string.Format("{0} load failure, reason: {1}", "stopwords_en_nltk.txt", e.Message));
+}
+catch (Exception e)
+{
+ Console.WriteLine(e.Message);
+}
+
+Console.ReadKey();
diff --git a/src/ConcurrentHashSet.Test/stopwords_en_nltk.txt b/src/ConcurrentHashSet.Test/stopwords_en_nltk.txt
new file mode 100644
index 0000000..49dd96e
--- /dev/null
+++ b/src/ConcurrentHashSet.Test/stopwords_en_nltk.txt
@@ -0,0 +1,127 @@
+i
+me
+my
+myself
+we
+our
+ours
+ourselves
+you
+your
+yours
+yourself
+yourselves
+he
+him
+his
+himself
+she
+her
+hers
+herself
+it
+its
+itself
+they
+them
+their
+theirs
+themselves
+what
+which
+who
+whom
+this
+that
+these
+those
+am
+is
+are
+was
+were
+be
+been
+being
+have
+has
+had
+having
+do
+does
+did
+doing
+a
+an
+the
+and
+but
+if
+or
+because
+as
+until
+while
+of
+at
+by
+for
+with
+about
+against
+between
+into
+through
+during
+before
+after
+above
+below
+to
+from
+up
+down
+in
+out
+on
+off
+over
+under
+again
+further
+then
+once
+here
+there
+when
+where
+why
+how
+all
+any
+both
+each
+few
+more
+most
+other
+some
+such
+no
+nor
+not
+only
+own
+same
+so
+than
+too
+very
+s
+t
+can
+will
+just
+don
+should
+now
\ No newline at end of file
diff --git a/src/ConcurrentHashSet/ConcurrentHashSet.cs b/src/ConcurrentHashSet/ConcurrentHashSet.cs
index 8876f6d..e74ce61 100644
--- a/src/ConcurrentHashSet/ConcurrentHashSet.cs
+++ b/src/ConcurrentHashSet/ConcurrentHashSet.cs
@@ -1,11 +1,8 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.Threading;
-namespace ConcurrentCollections
+namespace System.Collections.Concurrent
{
///
/// Represents a thread-safe hash-based unique collection.
@@ -274,7 +271,7 @@ private ConcurrentHashSet(int concurrencyLevel, int capacity, bool growLockArray
/// The
/// contains too many items.
public bool Add(T item) =>
- AddInternal(item, _comparer.GetHashCode(item), true);
+ AddInternal(item, true); // , _comparer.GetHashCode(item)
///
/// Removes all items from the .
@@ -322,8 +319,14 @@ public void Clear()
/// a value that has more complete data than the value you currently have, although their
/// comparer functions indicate they are equal.
///
- public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
+ public bool TryGetValue(T equalValue, out T? actualValue)
{
+ if (equalValue == null)
+ {
+ actualValue = default;
+ return false;
+ }
+
var hashcode = _comparer.GetHashCode(equalValue);
// We must capture the _buckets field in a local variable. It is set to a new table on each table resize.
@@ -357,6 +360,9 @@ public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
/// true if an item was removed successfully; otherwise, false.
public bool TryRemove(T item)
{
+ if (item == null)
+ return false;
+
var hashcode = _comparer.GetHashCode(item);
while (true)
{
@@ -569,9 +575,9 @@ void ICollection.CopyTo(T[] array, int arrayIndex)
private void InitializeFromCollection(IEnumerable collection)
{
- foreach (var item in collection)
+ foreach (T item in collection)
{
- AddInternal(item, _comparer.GetHashCode(item), false);
+ AddInternal(item, false); // , _comparer.GetHashCode(item)
}
if (_budget == 0)
@@ -581,8 +587,12 @@ private void InitializeFromCollection(IEnumerable collection)
}
}
- private bool AddInternal(T item, int hashcode, bool acquireLock)
+ private bool AddInternal(T item, bool acquireLock) // , int hashcode
{
+ if (item == null)
+ return false;
+
+ int hashcode = _comparer.GetHashCode(item);
while (true)
{
var tables = _tables;
diff --git a/src/ConcurrentHashSet/ConcurrentHashSet.csproj b/src/ConcurrentHashSet/ConcurrentHashSet.csproj
index 5c948b8..aa013a5 100644
--- a/src/ConcurrentHashSet/ConcurrentHashSet.csproj
+++ b/src/ConcurrentHashSet/ConcurrentHashSet.csproj
@@ -1,7 +1,7 @@
- ConcurrentCollections
+ System.Collections.Concurrent.ConcurrentHashSet
Bar Arnon
True
Copyright 2021 Bar Arnon
@@ -12,20 +12,20 @@
True
true
true
- ConcurrentHashSet
+ System.Collections.Concurrent.ConcurrentHashSet
MIT
True
concurrency
true
- ConcurrentCollections
+ System.Collections.Concurrent
snupkg
- netstandard1.0;netstandard2.0;net461
+ netstandard1.0;netstandard2.0;netstandard2.1;net6
ConcurrentHashSet
- 1.2.0
+ 1.2.1
-
+
\ No newline at end of file
diff --git a/src/ConcurrentHashSet/NullableAttributes.cs b/src/ConcurrentHashSet/NullableAttributes.cs
deleted file mode 100644
index ffe6f5f..0000000
--- a/src/ConcurrentHashSet/NullableAttributes.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-#if !NETSTANDARD2_1
-
-namespace System.Diagnostics.CodeAnalysis
-{
- /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it.
- [AttributeUsage(AttributeTargets.Parameter)]
- internal sealed class MaybeNullWhenAttribute : Attribute
- {
- /// Initializes the attribute with the specified return value condition.
- ///
- /// The return value condition. If the method returns this value, the associated parameter may be null.
- ///
- public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
-
- /// Gets the return value condition.
- public bool ReturnValue { get; }
- }
-}
-
-#endif
\ No newline at end of file