Skip to content

Commit 41c0d61

Browse files
Update for release.
1 parent 7b6345b commit 41c0d61

20 files changed

+195
-107
lines changed

benchmarking/Benchmarks/DictionaryParallelBenchmark.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ protected override IEnumerable<TimedResult> TestOnceInternal()
6565
Debug.Assert(has == (n < testSize));
6666
}));
6767

68+
yield return TimedResult.Measure("Pure Read",
69+
() => Parallel.For(0, testSize, i => _ = c[i]));
70+
6871
object[] items = Enumerable.Range(0, mixSize).Select(_ => new object()).ToArray();
6972
yield return TimedResult.Measure("50/50 Set/Get (In Parallel)", () =>
7073
{

source/CollectionWrapper.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public CollectionWrapper(TCollection source, bool owner = false)
2626

2727
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2828
protected virtual void AddInternal(in T item)
29-
=> InternalSource.Add(item);
29+
=> InternalUnsafeSource!.Add(item);
3030

3131
/// <inheritdoc />
3232
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -39,10 +39,11 @@ public virtual void Add(T item)
3939
/// <inheritdoc cref="IAddMultiple{T}.AddThese(T, T, T[])"/>
4040
public virtual void AddThese(T item1, T item2, params T[] items)
4141
{
42-
AddInternal(item1);
43-
AddInternal(item2);
42+
AssertIsAlive();
43+
AddInternal(in item1);
44+
AddInternal(in item2);
4445
foreach (T? i in items)
45-
AddInternal(i);
46+
AddInternal(in i);
4647
}
4748

4849
/// <summary>
@@ -54,8 +55,9 @@ public virtual void AddThese(T item1, T item2, params T[] items)
5455
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5556
public virtual void AddRange(IEnumerable<T> items)
5657
{
58+
AssertIsAlive();
5759
foreach (var i in items)
58-
AddInternal(i);
60+
AddInternal(in i);
5961
}
6062

6163
/// <inheritdoc />

source/DictionaryToHashSetWrapper.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ public bool IsReadOnly
2626
/// <inheritdoc />
2727
public virtual bool Add(T item)
2828
{
29-
if (InternalSource.ContainsKey(item))
29+
var source = InternalSource;
30+
if (source.ContainsKey(item))
3031
return false;
3132

3233
try
3334
{
34-
InternalSource.Add(item, true);
35+
source.Add(item, true);
3536
}
3637
catch
3738
{
@@ -80,9 +81,10 @@ public void ExceptWith(IEnumerable<T> other)
8081
/// <inheritdoc />
8182
public void IntersectWith(IEnumerable<T> other)
8283
{
84+
var source = InternalSource;
8385
foreach (T? e in other)
8486
{
85-
if (!InternalSource.ContainsKey(e))
87+
if (!source.ContainsKey(e))
8688
Remove(e);
8789
}
8890
}
@@ -108,9 +110,10 @@ public void IntersectWith(IEnumerable<T> other)
108110
/// <inheritdoc />
109111
public void SymmetricExceptWith(IEnumerable<T> other)
110112
{
111-
foreach (T? e in other)
113+
var source = InternalSource;
114+
foreach (T? e in other)
112115
{
113-
if (InternalSource.ContainsKey(e))
116+
if (source.ContainsKey(e))
114117
Add(e);
115118
else
116119
Remove(e);

source/IndexedDictionary.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class IndexedDictionary<TKey, TValue>
1717
private readonly List<KeyValuePair<TKey, TValue>> _entries;
1818
private readonly Dictionary<TKey, int> _indexes;
1919

20+
[ExcludeFromCodeCoverage]
2021
public IndexedDictionary(int capacity)
2122
: base(capacity)
2223
{

source/ListWrapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class ListWrapper<T, TList>
77
: CollectionWrapper<T, TList>, IList<T>
88
where TList : class, IList<T>
99
{
10+
[ExcludeFromCodeCoverage]
1011
public ListWrapper(TList source, bool owner = false)
1112
: base(source, owner)
1213
{

source/Open.Collections.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<PackageProjectUrl>https://github.com/Open-NET-Libraries/Open.Collections/</PackageProjectUrl>
1818
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Collections/</RepositoryUrl>
1919
<RepositoryType>git</RepositoryType>
20-
<Version>2.14.0</Version>
20+
<Version>3.0.0</Version>
2121
<PackageReleaseNotes></PackageReleaseNotes>
2222
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2323
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@@ -45,7 +45,7 @@
4545

4646
<ItemGroup>
4747
<PackageReference Include="Open.Text" Version="6.2.0" />
48-
<PackageReference Include="Open.Threading" Version="2.1.1" />
48+
<PackageReference Include="Open.Threading" Version="2.1.2" />
4949
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
5050
</ItemGroup>
5151

source/OrderedDictionary.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ public class OrderedDictionary<TKey, TValue>
1111
: DictionaryWrapperBase<TKey, TValue, LinkedList<KeyValuePair<TKey, TValue>>>, IDictionary<TKey, TValue>
1212
{
1313
/// <inheritdoc />
14+
[ExcludeFromCodeCoverage]
1415
public OrderedDictionary()
1516
: base(new LinkedList<KeyValuePair<TKey, TValue>>(), true)
1617
=> _lookup = new();
18+
1719
/// <inheritdoc />
20+
[ExcludeFromCodeCoverage]
1821
public OrderedDictionary(int capacity)
1922
: base(new LinkedList<KeyValuePair<TKey, TValue>>(), true)
2023
=> _lookup = new(capacity);

source/ReadOnlyCollectionWrapper.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ public class ReadOnlyCollectionWrapper<T, TCollection>
1212
: DisposableBase, IReadOnlyCollection<T>
1313
where TCollection : class, ICollection<T>
1414
{
15-
[SuppressMessage("Roslynator", "RCS1169:Make field read-only.")]
16-
private TCollection? _source;
15+
protected TCollection? InternalUnsafeSource;
1716
protected readonly bool SourceOwned;
1817

1918
protected TCollection InternalSource
20-
=> _source ?? throw new ObjectDisposedException(GetType().ToString());
19+
=> InternalUnsafeSource ?? throw new ObjectDisposedException(GetType().ToString());
2120

2221
/// <summary>
2322
/// Constructs a wrapper for read-only access to a collection.
@@ -31,7 +30,7 @@ protected TCollection InternalSource
3130
[ExcludeFromCodeCoverage]
3231
public ReadOnlyCollectionWrapper(TCollection source, bool owner = false)
3332
{
34-
_source = source ?? throw new ArgumentNullException(nameof(source));
33+
InternalUnsafeSource = source ?? throw new ArgumentNullException(nameof(source));
3534
SourceOwned = owner;
3635
}
3736

@@ -102,7 +101,7 @@ public virtual void Export(ICollection<T> to)
102101
[ExcludeFromCodeCoverage]
103102
protected override void OnDispose()
104103
{
105-
var source = Nullify(ref _source!);
104+
var source = Nullify(ref InternalUnsafeSource!);
106105
if (SourceOwned && source is IDisposable d) d.Dispose();
107106
}
108107

@@ -117,7 +116,7 @@ public TCollection ExtractAndDispose()
117116
if (SourceOwned) throw new NotSupportedException("The underlying collection is owned by this wrapper.");
118117
using (this)
119118
{
120-
return Nullify(ref _source!);
119+
return Nullify(ref InternalUnsafeSource!);
121120
}
122121
}
123122
#endregion

source/Synchronized/LockSynchronizedCollectionWrapper.cs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Open.Threading;
2+
using System;
23
using System.Collections.Generic;
34
using System.Collections.Immutable;
45
using System.Diagnostics.CodeAnalysis;
@@ -13,6 +14,12 @@ public class LockSynchronizedCollectionWrapper<T, TCollection>
1314
protected LockSynchronizedCollectionWrapper(TCollection source, bool owner = false)
1415
: base(source, owner) { }
1516

17+
protected override void OnBeforeDispose()
18+
{
19+
ThreadSafety.Lock(Sync, () => { }, 1000);
20+
base.OnBeforeDispose();
21+
}
22+
1623
#region Implementation of ICollection<T>
1724

1825
/// <inheritdoc />
@@ -23,15 +30,15 @@ public override void Add(T item)
2330
}
2431

2532
/// <inheritdoc />
26-
[SuppressMessage("Roslynator", "RCS1235:Optimize method call.")]
2733
public override void AddThese(T item1, T item2, params T[] items)
2834
{
2935
lock (Sync)
3036
{
31-
base.Add(item1);
32-
base.Add(item2);
37+
AssertIsAlive();
38+
AddInternal(in item1);
39+
AddInternal(in item2);
3340
foreach (T? i in items)
34-
base.Add(i);
41+
AddInternal(in i);
3542
}
3643
}
3744

@@ -152,8 +159,9 @@ public virtual bool IfContains(T item, Action<TCollection> action)
152159
{
153160
lock (Sync)
154161
{
155-
if (!InternalSource.Contains(item)) return false;
156-
action(InternalSource);
162+
var source = InternalSource;
163+
if (!source.Contains(item)) return false;
164+
action(source);
157165
return true;
158166
}
159167
}
@@ -163,8 +171,9 @@ public virtual bool IfNotContains(T item, Action<TCollection> action)
163171
{
164172
lock (Sync)
165173
{
166-
if (InternalSource.Contains(item)) return false;
167-
action(InternalSource);
174+
var source = InternalSource;
175+
if (source.Contains(item)) return false;
176+
action(source);
168177
return true;
169178
}
170179
}

source/Synchronized/LockSynchronizedDictionaryWrapper.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,23 @@ public virtual TValue this[TKey key]
2525
}
2626
}
2727

28+
ICollection<TKey>? _keys;
2829
/// <inheritdoc />
29-
public virtual ICollection<TKey> Keys
30-
=> InternalSource.Keys;
30+
public ICollection<TKey> Keys => _keys ??= GetKeys();
31+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
32+
protected virtual ICollection<TKey> GetKeys()
33+
=> new ReadOnlyCollectionAdapter<TKey>(
34+
ThrowIfDisposed(InternalSource.Keys),
35+
() => InternalSource.Count);
3136

37+
ICollection<TValue>? _values;
3238
/// <inheritdoc />
33-
public virtual ICollection<TValue> Values
34-
=> InternalSource.Values;
39+
public ICollection<TValue> Values => _values ??= GetValues();
40+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
41+
protected virtual ICollection<TValue> GetValues()
42+
=> new ReadOnlyCollectionAdapter<TValue>(
43+
ThrowIfDisposed(InternalSource.Values),
44+
() => InternalSource.Count);
3545

3646
/// <inheritdoc />
3747
[MethodImpl(MethodImplOptions.AggressiveInlining)]

0 commit comments

Comments
 (0)