Skip to content

Commit 332d5a8

Browse files
committed
Merge branch 'develop'
2 parents 6c5c41b + e6aa65a commit 332d5a8

File tree

18 files changed

+789
-255
lines changed

18 files changed

+789
-255
lines changed

.github/workflows/dotnet.yml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: .NET CI
2+
'on':
3+
push:
4+
branches-ignore:
5+
- dependabot/**
6+
- gh-pages
7+
tags-ignore:
8+
- v*
9+
pull_request:
10+
branches:
11+
- main
12+
jobs:
13+
build-and-test-linux:
14+
if: |
15+
(github.event_name != 'pull_request' && !github.event.pull_request.head.repo.fork)
16+
|| (github.event_name == 'pull_request' && (github.event.pull_request.head.repo.fork
17+
|| startsWith(github.head_ref, 'dependabot/')))
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
persist-credentials: false
26+
27+
- name: Setup .NET
28+
uses: actions/setup-dotnet@v4
29+
with:
30+
dotnet-version: 8.0.x
31+
32+
- name: Install Mono (required for .NET Framework tests on Linux)
33+
run: |
34+
sudo apt update
35+
sudo apt install -y mono-complete
36+
37+
- name: Install GitVersion
38+
uses: gittools/actions/gitversion/[email protected]
39+
with:
40+
versionSpec: 6.0.x
41+
42+
- name: Cache NuGet packages
43+
uses: actions/cache@v3
44+
with:
45+
path: ~/.nuget/packages
46+
key: '${{ runner.os }}-nuget-${{ hashFiles(''**/*.csproj'', ''**/*.sln'') }}'
47+
restore-keys: |
48+
${{ runner.os }}-nuget-
49+
50+
- name: Determine Version
51+
id: version_step
52+
run: |
53+
chown -R $(whoami) $(pwd)
54+
dotnet-gitversion /output json
55+
56+
- name: Restore dependencies
57+
run: dotnet restore
58+
59+
- name: Build Solution
60+
run: |
61+
echo "Version: ${{ steps.version_step.outputs.fullSemVer }}\nAssembley Version: ${{ steps.version_step.outputs.fullSemVer }}"
62+
dotnet build --configuration Debug --no-restore
63+
64+
- name: Test
65+
run: |
66+
dotnet --info
67+
mono ~/.nuget/packages/xunit.runner.console/2.9.3/tools/net472/xunit.console.exe ${{github.workspace}}/tests/SwiftCollections.Tests/bin/Debug/net48/SwiftCollections.Tests.dll
68+
69+
build-and-test-windows:
70+
if: |
71+
(github.event_name != 'pull_request' && !github.event.pull_request.head.repo.fork)
72+
|| (github.event_name == 'pull_request' && (github.event.pull_request.head.repo.fork
73+
|| startsWith(github.head_ref, 'dependabot/')))
74+
runs-on: windows-latest
75+
steps:
76+
- name: Checkout repository
77+
uses: actions/checkout@v4
78+
with:
79+
fetch-depth: 0
80+
persist-credentials: false
81+
82+
- name: Setup .NET
83+
uses: actions/setup-dotnet@v4
84+
with:
85+
dotnet-version: 8.0.x
86+
87+
- name: Install GitVersion
88+
uses: gittools/actions/gitversion/[email protected]
89+
with:
90+
versionSpec: 6.0.x
91+
92+
- name: Cache NuGet packages
93+
uses: actions/cache@v3
94+
with:
95+
path: ~/.nuget/packages
96+
key: '${{ runner.os }}-nuget-${{ hashFiles(''**/*.csproj'', ''**/*.sln'') }}'
97+
restore-keys: |
98+
${{ runner.os }}-nuget-
99+
100+
- name: Determine Version
101+
run: |
102+
chown -R $(whoami) $(pwd)
103+
dotnet-gitversion /output json
104+
105+
- name: Restore dependencies
106+
run: dotnet restore
107+
108+
- name: Build Solution
109+
run: |
110+
echo "Version:${{ env.GitVersion_FullSemVer }}\nAssembley Version:${{env.GitVersion_AssemblySemFileVer }}"
111+
dotnet build --configuration Release --no-restore
112+
113+
- name: Test
114+
run: |
115+
dotnet --info
116+
dotnet test ${{github.workspace}}\tests\SwiftCollections.Tests\bin\Release\net48\SwiftCollections.Tests.dll --verbosity normal

src/SwiftCollections/Dimensions/Array2d.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public Array2D(T[,] source)
4848
int height = source.GetLength(1);
4949

5050
Initialize(width, height);
51+
52+
for (int x = 0; x < width; x++)
53+
for (int y = 0; y < height; y++)
54+
this[x, y] = source[x, y];
5155
}
5256

5357
#endregion

src/SwiftCollections/Pool/DefaultImplementations/SwiftArrayPool.cs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Runtime.CompilerServices;
4+
using System.Threading;
45

56
namespace SwiftCollections.Pool
67
{
@@ -11,13 +12,22 @@ namespace SwiftCollections.Pool
1112
/// <typeparam name="T">The type of elements in the arrays being pooled. Must have a parameterless constructor.</typeparam>
1213
public sealed class SwiftArrayPool<T> : IDisposable where T : new()
1314
{
14-
#region Fields
15+
#region Singleton Instance
1516

1617
/// <summary>
1718
/// A lazily initialized singleton instance of the array pool.
1819
/// </summary>
19-
private static readonly Lazy<SwiftArrayPool<T>> _instance =
20-
new Lazy<SwiftArrayPool<T>>(() => new SwiftArrayPool<T>());
20+
private static readonly LazyDisposable<SwiftArrayPool<T>> _instance =
21+
new LazyDisposable<SwiftArrayPool<T>>(() => new SwiftArrayPool<T>(), LazyThreadSafetyMode.ExecutionAndPublication);
22+
23+
/// <summary>
24+
/// Gets the shared instance of the pool.
25+
/// </summary>
26+
public static SwiftArrayPool<T> Shared => _instance.Value;
27+
28+
#endregion
29+
30+
#region Fields
2131

2232
/// <summary>
2333
/// A collection of object pools, keyed by the size of the arrays they manage.
@@ -52,17 +62,14 @@ public SwiftArrayPool(
5262
PoolMaxCapacity = poolMaxCapacity;
5363

5464
CreateFunc = createFunc ?? (size => new T[size]);
55-
ActionOnRelease = actionOnRelease ?? (array => Array.Clear(array, 0, array.Length));
65+
ActionOnRelease = actionOnRelease ?? (array =>
66+
Array.Clear(array, 0, array.Length));
5667
ActionOnDestroy = actionOnDestroy;
5768
}
5869

5970
#endregion
6071

6172
#region Properties
62-
/// <summary>
63-
/// Gets the shared singleton instance of the array pool.
64-
/// </summary>
65-
public static SwiftArrayPool<T> Shared => _instance.Value;
6673

6774
/// <summary>
6875
/// Gets the function used to create new arrays.
@@ -125,9 +132,9 @@ public void Release(T[] array)
125132
/// </summary>
126133
public void Clear()
127134
{
128-
if (_disposed) ThrowHelper.ThrowObjectDisposedException(nameof(SwiftArrayPool<T>));
135+
if (_disposed) return;
129136

130-
foreach (var pool in _sizePools.Values)
137+
foreach (SwiftObjectPool<T[]> pool in _sizePools.Values)
131138
pool.Clear();
132139

133140
_sizePools.Clear();
@@ -159,24 +166,18 @@ private SwiftObjectPool<T[]> CreatePoolForSize(int size)
159166
/// </summary>
160167
public void Dispose()
161168
{
162-
OnDispose();
163-
GC.SuppressFinalize(this); // Avoids calling the finalizer if already disposed.
164-
}
165-
166-
private void OnDispose()
167-
{
168-
if (_disposed)
169-
return;
169+
if (_disposed) return;
170170

171171
_disposed = true;
172-
173-
foreach (var pool in _sizePools.Values)
172+
foreach (SwiftObjectPool<T[]> pool in _sizePools.Values)
174173
pool.Dispose();
175-
176174
_sizePools.Clear();
175+
176+
// Suppress finalization to prevent unnecessary GC overhead
177+
GC.SuppressFinalize(this);
177178
}
178179

179-
~SwiftArrayPool() => OnDispose(); // Called by GC if Dispose() wasn't called explicitly.
180+
~SwiftArrayPool() => Dispose();
180181

181182
#endregion
182183
}

src/SwiftCollections/Pool/DefaultImplementations/SwiftCollectionPool.cs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23

34
namespace SwiftCollections.Pool
45
{
@@ -9,17 +10,27 @@ namespace SwiftCollections.Pool
910
/// </summary>
1011
/// <typeparam name="TCollection">The type of the collection being pooled. Must implement <see cref="ICollection{TItem}"/> and have a parameterless constructor.</typeparam>
1112
/// <typeparam name="TItem">The type of items contained in the collection.</typeparam>
12-
public static class SwiftCollectionPool<TCollection, TItem> where TCollection : class, ICollection<TItem>, new()
13+
public abstract class SwiftCollectionPool<TCollection, TItem> where TCollection : class, ICollection<TItem>, new()
1314
{
14-
#region Fields
15+
#region Singleton Instances
1516

1617
/// <summary>
1718
/// Internal object pool for managing the lifecycle of pooled collections.
19+
/// Uses <see cref="Lazy{T}"/> to ensure lazy initialization.
1820
/// </summary>
19-
private static readonly SwiftObjectPool<TCollection> _collectionPool = new SwiftObjectPool<TCollection>(
20-
createFunc: () => new TCollection(),
21-
actionOnRelease: collection => collection.Clear()
22-
);
21+
private LazyDisposable<SwiftObjectPool<TCollection>> _lazyCollectionPool =
22+
new LazyDisposable<SwiftObjectPool<TCollection>>(() =>
23+
{
24+
return new SwiftObjectPool<TCollection>(
25+
createFunc: () => new TCollection(),
26+
actionOnRelease: collection => collection.Clear()
27+
);
28+
});
29+
30+
/// <summary>
31+
/// Gets the shared instance of the pool.
32+
/// </summary>
33+
public SwiftObjectPool<TCollection> CollectionPool => _lazyCollectionPool.Value;
2334

2435
#endregion
2536

@@ -29,36 +40,57 @@ namespace SwiftCollections.Pool
2940
/// Rents a collection from the pool. If the pool is empty, a new collection is created.
3041
/// </summary>
3142
/// <returns>A collection instance of type <typeparamref name="TCollection"/>.</returns>
32-
public static TCollection Rent()
43+
public virtual TCollection Rent()
3344
{
34-
return _collectionPool.Rent();
45+
return CollectionPool.Rent();
3546
}
3647

3748
/// <summary>
3849
/// Rents a collection from the pool and wraps it in a <see cref="SwiftPooledObject{TCollection}"/> for automatic release.
3950
/// </summary>
4051
/// <param name="value">The rented collection.</param>
4152
/// <returns>A <see cref="SwiftPooledObject{TCollection}"/> instance wrapping the rented collection.</returns>
42-
public static SwiftPooledObject<TCollection> Get(out TCollection value)
53+
public virtual SwiftPooledObject<TCollection> Get(out TCollection value)
4354
{
44-
return _collectionPool.Rent(out value);
55+
return CollectionPool.Rent(out value);
4556
}
4657

4758
/// <summary>
4859
/// Releases a collection back to the pool for reuse.
4960
/// </summary>
5061
/// <param name="toRelease">The collection to release.</param>
51-
public static void Release(TCollection toRelease)
62+
public virtual void Release(TCollection toRelease)
5263
{
53-
_collectionPool.Release(toRelease);
64+
CollectionPool.Release(toRelease);
5465
}
5566

5667
/// <summary>
5768
/// Clears all collections from the pool.
5869
/// </summary>
59-
public static void Clear()
70+
public virtual void Clear() => CollectionPool?.Clear();
71+
72+
#endregion
73+
74+
#region IDisposable Implementation
75+
76+
/// <summary>
77+
/// Releases all resources used by the SwiftCollectionPool.
78+
/// </summary>
79+
public virtual void Flush()
6080
{
61-
_collectionPool.Clear();
81+
if (_lazyCollectionPool.IsValueCreated)
82+
{
83+
_lazyCollectionPool.Value.Dispose();
84+
85+
_lazyCollectionPool = new LazyDisposable<SwiftObjectPool<TCollection>>(() =>
86+
{
87+
return new SwiftObjectPool<TCollection>(
88+
createFunc: () => new TCollection(),
89+
actionOnRelease: collection => collection.Clear()
90+
);
91+
});
92+
}
93+
6294
}
6395

6496
#endregion

0 commit comments

Comments
 (0)