1- using System . Collections ;
1+ using System ;
2+ using System . Collections ;
23using System . Collections . Concurrent ;
34using System . Collections . Generic ;
45using System . Linq ;
6+ using System . Threading ;
57
68namespace Xpand . Utils . GeneralDataStructures {
7- public class MultiValueDictionary < TKey , TValue > : ConcurrentDictionary < TKey , HashSet < TValue > > , ILookup < TKey , TValue > {
9+ public class ConcurrentHashSet < T > : IDisposable , IEnumerable < T > {
10+ private readonly HashSet < T > _hashSet = new HashSet < T > ( ) ;
11+ private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim ( LockRecursionPolicy . SupportsRecursion ) ;
12+
13+ public int Count {
14+ get {
15+ _lock . EnterReadLock ( ) ;
16+
17+ try {
18+ return _hashSet . Count ;
19+ }
20+ finally {
21+ if ( _lock . IsReadLockHeld ) _lock . ExitReadLock ( ) ;
22+ }
23+ }
24+ }
25+
26+ public void Dispose ( ) {
27+ Dispose ( true ) ;
28+ GC . SuppressFinalize ( this ) ;
29+ }
30+
31+ public IEnumerator < T > GetEnumerator ( ) {
32+ _lock . EnterWriteLock ( ) ;
33+
34+ try {
35+ return _hashSet . GetEnumerator ( ) ;
36+ }
37+ finally {
38+ if ( _lock . IsWriteLockHeld ) _lock . ExitWriteLock ( ) ;
39+ }
40+ }
41+
42+ IEnumerator IEnumerable . GetEnumerator ( ) {
43+ return GetEnumerator ( ) ;
44+ }
45+
46+ public bool TryAdd ( T item ) {
47+ _lock . EnterWriteLock ( ) ;
48+
49+ try {
50+ return _hashSet . Add ( item ) ;
51+ }
52+ finally {
53+ if ( _lock . IsWriteLockHeld ) _lock . ExitWriteLock ( ) ;
54+ }
55+ }
56+
57+ public void Clear ( ) {
58+ _lock . EnterWriteLock ( ) ;
59+
60+ try {
61+ _hashSet . Clear ( ) ;
62+ }
63+ finally {
64+ if ( _lock . IsWriteLockHeld ) _lock . ExitWriteLock ( ) ;
65+ }
66+ }
67+
68+ public bool Contains ( T item ) {
69+ _lock . EnterReadLock ( ) ;
70+
71+ try {
72+ return _hashSet . Contains ( item ) ;
73+ }
74+ finally {
75+ if ( _lock . IsReadLockHeld ) _lock . ExitReadLock ( ) ;
76+ }
77+ }
78+
79+ public bool TryRemove ( T item ) {
80+ _lock . EnterWriteLock ( ) ;
81+
82+ try {
83+ return _hashSet . Remove ( item ) ;
84+ }
85+ finally {
86+ if ( _lock . IsWriteLockHeld ) _lock . ExitWriteLock ( ) ;
87+ }
88+ }
89+
90+ public T FirstOrDefault ( Func < T , bool > predicate ) {
91+ _lock . EnterReadLock ( ) ;
92+
93+ try {
94+ return _hashSet . FirstOrDefault ( predicate ) ;
95+ }
96+ finally {
97+ if ( _lock . IsReadLockHeld ) _lock . ExitReadLock ( ) ;
98+ }
99+ }
100+
101+ protected virtual void Dispose ( bool disposing ) {
102+ if ( disposing ) _lock ? . Dispose ( ) ;
103+ }
104+ }
105+
106+ public class
107+ MultiValueDictionary < TKey , TValue > : ConcurrentDictionary < TKey , ConcurrentHashSet < TValue > > , ILookup < TKey , TValue > {
8108 bool ILookup < TKey , TValue > . Contains ( TKey key ) {
9109 return ContainsKey ( key ) ;
10110 }
@@ -23,11 +123,11 @@ IEnumerator IEnumerable.GetEnumerator() {
23123
24124 public void Add ( TKey key , TValue value ) {
25125 if ( ! TryGetValue ( key , out var container ) ) {
26- container = new HashSet < TValue > ( ) ;
126+ container = new ConcurrentHashSet < TValue > ( ) ;
27127 TryAdd ( key , container ) ;
28128 }
29129
30- container . Add ( value ) ;
130+ container . TryAdd ( value ) ;
31131 }
32132
33133 public void AddRange ( TKey key , IEnumerable < TValue > values ) {
@@ -44,10 +144,8 @@ public bool ContainsValue(TKey key, TValue value) {
44144
45145 public void Remove ( TKey key , TValue value ) {
46146 if ( TryGetValue ( key , out var container ) ) {
47- container . Remove ( value ) ;
48- if ( container . Count <= 0 ) {
49- TryRemove ( key , out container ) ;
50- }
147+ container . TryRemove ( value ) ;
148+ if ( container . Count <= 0 ) TryRemove ( key , out container ) ;
51149 }
52150 }
53151
@@ -59,8 +157,8 @@ public void Merge(MultiValueDictionary<TKey, TValue> toMergeWith) {
59157 Add ( pair . Key , value ) ;
60158 }
61159
62- public HashSet < TValue > GetValues ( TKey key , bool returnEmptySet ) {
63- if ( ! TryGetValue ( key , out var toReturn ) && returnEmptySet ) toReturn = new HashSet < TValue > ( ) ;
160+ public ConcurrentHashSet < TValue > GetValues ( TKey key , bool returnEmptySet ) {
161+ if ( ! TryGetValue ( key , out var toReturn ) && returnEmptySet ) toReturn = new ConcurrentHashSet < TValue > ( ) ;
64162 return toReturn ;
65163 }
66164 }
0 commit comments