Skip to content
This repository was archived by the owner on Feb 14, 2022. It is now read-only.

Commit 271dc99

Browse files
authored
Merge pull request #118 from JacopoWolf/dev/optimization
Optimizations
2 parents 110555f + f066dde commit 271dc99

27 files changed

Lines changed: 430 additions & 335 deletions

StackInjector/Behaviours/IInstancesHolder.cs

Lines changed: 0 additions & 36 deletions
This file was deleted.

StackInjector/Behaviours/SingleInstanceHolder.cs

Lines changed: 0 additions & 69 deletions
This file was deleted.

StackInjector/Core/AsyncStackWrapperCore.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@ public CancellationToken PendingTasksCancellationToken
1919
=> this.cancelPendingTasksSource.Token;
2020

2121
// used to lock access to tasks
22-
private readonly object listAccessLock = new object();
22+
private readonly object _listAccessLock = new object();
2323

2424
// used to endure Elaborated() and Elaborate() are called together
25-
private bool exclusiveExecution;
25+
private bool _exclusiveExecution;
26+
27+
public bool IsElaborating => this._exclusiveExecution;
2628

2729
// asyncronously waited for new events if TaskList is empty
28-
private readonly SemaphoreSlim emptyListAwaiter = new SemaphoreSlim(0);
30+
private readonly SemaphoreSlim _emptyListAwaiter = new SemaphoreSlim(0);
2931

3032
// pending tasks
3133
protected internal LinkedList<Task<T>> tasks = new LinkedList<Task<T>>();
3234

3335

34-
internal AsyncStackWrapperCore ( InjectionCore core, Type toRegister ) : base(core, toRegister)
35-
{
36-
// register an event that in case the list is empty, release the empty event listener.
36+
// register an event that in case the list is empty, release the empty event listener.
37+
internal AsyncStackWrapperCore ( InjectionCore core, Type toRegister ) : base(core, toRegister) =>
3738
this.cancelPendingTasksSource.Token.Register(this.ReleaseListAwaiter);
38-
}
3939

4040

4141

@@ -49,11 +49,11 @@ public override void Dispose ()
4949
{
5050

5151
// managed resources
52-
this.cancelPendingTasksSource.Cancel();
52+
this.cancelPendingTasksSource.Cancel(); // cancel all pending tasks
5353
this.ReleaseListAwaiter(); // in case it's waiting on the empty list
5454

5555
this.cancelPendingTasksSource.Dispose();
56-
this.emptyListAwaiter.Dispose();
56+
this._emptyListAwaiter.Dispose();
5757

5858

5959
// big objects

StackInjector/Core/AsyncStackWrapperCore.logic.cs

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ namespace StackInjector.Core
99
internal abstract partial class AsyncStackWrapperCore<T>
1010
{
1111
// call the semaphore
12-
protected internal void ReleaseListAwaiter ()
13-
{
14-
this.emptyListAwaiter.Release();
15-
}
12+
protected internal void ReleaseListAwaiter () => this._emptyListAwaiter.Release();
13+
1614

17-
public void Submit ( Task<T> work )
15+
internal void Submit ( Task<T> work )
1816
{
19-
lock( this.listAccessLock )
17+
lock( this._listAccessLock )
2018
this.tasks.AddLast(work);
2119

2220
// if the list was empty just an item ago, signal it's not anymore.
@@ -25,31 +23,35 @@ public void Submit ( Task<T> work )
2523
this.ReleaseListAwaiter();
2624
}
2725

26+
2827
public bool AnyTaskLeft ()
2928
{
30-
lock( this.listAccessLock )
29+
lock( this._listAccessLock )
3130
return this.tasks.Any();
3231
}
3332

3433
public bool AnyTaskCompleted ()
3534
{
36-
return this.tasks.Any(t => t.IsCompleted);
35+
lock( this._listAccessLock )
36+
return this.tasks.Any(t => t.IsCompleted);
3737
}
3838

3939
// todo add a method to safely exit the await loop to be able to re-join later or maybe an Unloack() of some sort
4040
//! should check if exiting an await foreach loop and re-entering will not hack the control or lose data
4141
public async IAsyncEnumerable<T> Elaborated ()
4242
{
4343
this.EnsureExclusiveExecution(true);
44-
44+
4545
while( !this.cancelPendingTasksSource.IsCancellationRequested )
4646
{
4747
// avoid deadlocks
4848
if( this.AnyTaskLeft() )
4949
{
5050
var completed = await Task.WhenAny(this.tasks).ConfigureAwait(false);
5151

52-
lock( this.listAccessLock )
52+
53+
54+
lock( this._listAccessLock )
5355
this.tasks.Remove(completed);
5456

5557
yield return completed.Result;
@@ -62,24 +64,15 @@ public async IAsyncEnumerable<T> Elaborated ()
6264
}
6365
}
6466

65-
lock( this.listAccessLock )
66-
this.exclusiveExecution = false;
67+
lock( this._listAccessLock )
68+
this._exclusiveExecution = false;
6769

6870
}
6971

70-
public Task Elaborate ()
72+
public async Task Elaborate ()
7173
{
72-
// must run syncronously
73-
this.EnsureExclusiveExecution();
74-
75-
return
76-
Task.Run(async () =>
77-
{
78-
79-
await foreach( var res in this.Elaborated() )
80-
this.OnElaborated?.Invoke(res);
81-
});
82-
74+
await foreach( var res in this.Elaborated() )
75+
this.OnElaborated?.Invoke(res);
8376
}
8477

8578

@@ -88,7 +81,7 @@ private async Task<bool> OnNoTasksLeft ()
8881
{
8982
// to not repeat code
9083
Task listAwaiter ()
91-
=> this.emptyListAwaiter.WaitAsync();
84+
=> this._emptyListAwaiter.WaitAsync();
9285

9386

9487
switch( this.Settings._asyncWaitingMethod )
@@ -118,13 +111,13 @@ Task listAwaiter ()
118111

119112
private void EnsureExclusiveExecution ( bool set = false )
120113
{
121-
lock( this.listAccessLock ) // reused lock
114+
lock( this._listAccessLock ) // reused lock
122115
{
123-
if( this.exclusiveExecution )
116+
if( this._exclusiveExecution )
124117
throw new InvalidOperationException();
125118

126119
if( set )
127-
this.exclusiveExecution = set;
120+
this._exclusiveExecution = set;
128121
}
129122
}
130123

StackInjector/Core/Cloning/ClonedCore.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public IAsyncStackWrapper<TEntry, TIn, TOut> ToAsyncWrapper<TEntry, TIn, TOut> (
1919
StackDigest = digest
2020
};
2121

22-
this.clonedCore.EntryPoint = typeof(TEntry);
22+
this.clonedCore.EntryType = typeof(TEntry);
2323
this.clonedCore.ServeAll();
2424

2525
return wrapper;
@@ -29,7 +29,7 @@ public IStackWrapper<T> ToWrapper<T> ()
2929
{
3030
var wrapper = new StackWrapper<T>(this.clonedCore);
3131

32-
this.clonedCore.EntryPoint = typeof(T);
32+
this.clonedCore.EntryType = typeof(T);
3333
this.clonedCore.ServeAll();
3434

3535
return wrapper;

StackInjector/Core/IAsyncStackWrapperCore.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,12 @@ public interface IAsyncStackWrapperCore<T> : IStackWrapperCore
1616
/// </summary>
1717
event Action<T> OnElaborated;
1818

19+
1920
/// <summary>
2021
/// Used to signal cancellation of every pending task
2122
/// </summary>
2223
CancellationToken PendingTasksCancellationToken { get; }
2324

24-
/// <summary>
25-
/// submit new work to this wrapper
26-
/// </summary>
27-
/// <param name="work"></param>
28-
void Submit ( Task<T> work );
29-
3025
/// <summary>
3126
/// The loop you ca use to <c>await foreach</c> tasks in elaboration, converted to the specified type.
3227
/// When the pending tasks list is empty, unless <see cref="IDisposable.Dispose"/> is explocitly called
@@ -44,6 +39,16 @@ public interface IAsyncStackWrapperCore<T> : IStackWrapperCore
4439
/// <exception cref="InvalidOperationException"></exception>
4540
Task Elaborate ();
4641

42+
43+
44+
45+
/// <summary>
46+
/// is this wrapper is already elaborating queued tasks.<br/>
47+
/// If true, then calling <see cref="Elaborate"/> or <see cref="Elaborated"/>
48+
/// will throw a <see cref="InvalidOperationException"/>
49+
/// </summary>
50+
bool IsElaborating { get; }
51+
4752
/// <summary>
4853
/// check if there are tasks left to elaborate
4954
/// </summary>

StackInjector/Core/StackWrapperCore.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ public StackWrapperCore ( InjectionCore core, Type toRegister )
2424

2525
// setting for referencing the calling wrapper as a service
2626
if( this.Core.settings._registerWrapAsService )
27-
this.Core.instances.AddInstance(toRegister, this);
27+
{
28+
this.Core.instances.AddType(toRegister);
29+
this.Core.instances[toRegister].Clear();
30+
this.Core.instances[toRegister].AddFirst(this);
31+
}
2832
}
2933

3034

StackInjector/Core/InjectionCore.cs renamed to StackInjector/Core/injectionCore/InjectionCore.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Reflection;
44
using StackInjector.Attributes;
5-
using StackInjector.Behaviours;
65
using StackInjector.Exceptions;
76
using StackInjector.Settings;
87

@@ -15,27 +14,26 @@ namespace StackInjector.Core
1514
internal partial class InjectionCore
1615
{
1716
// entry point object of this core
18-
private Type _entryPoint;
19-
internal Type EntryPoint
17+
private Type _entryType;
18+
internal Type EntryType
2019
{
2120
get
22-
=> this._entryPoint;
21+
=> this._entryType;
2322
set
2423
{
2524
var serviceAtt = value.GetCustomAttribute<ServiceAttribute>();
2625
if( serviceAtt != null && serviceAtt.Pattern == InstantiationPattern.AlwaysCreate )
2726
throw new InvalidEntryTypeException(value, $"Entry point {value.Name} cannot have {InstantiationPattern.AlwaysCreate} as instantiation pattern.");
2827

29-
this._entryPoint = value;
28+
this._entryType = value;
3029
}
3130
}
3231

33-
3432
// manage settings
3533
internal StackWrapperSettings settings;
3634

3735
// holds instances
38-
internal IInstancesHolder instances;
36+
internal InstancesHolder instances;
3937

4038
// tracks instantiated objects
4139
internal readonly List<object> instancesDiff;
@@ -49,7 +47,7 @@ internal InjectionCore ( StackWrapperSettings settings )
4947
{
5048
this.settings = settings;
5149

52-
this.instances = new SingleInstanceHolder();
50+
this.instances = new InstancesHolder();
5351

5452
if( this.settings._trackInstancesDiff )
5553
this.instancesDiff = new List<object>();

0 commit comments

Comments
 (0)