Skip to content

Commit

Permalink
Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
TheArcaneBrony committed May 28, 2024
1 parent 68eca20 commit 808f94b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.5" />
</ItemGroup>

<ItemGroup>
Expand Down
53 changes: 33 additions & 20 deletions ArcaneLibs/Collections/SemaphoreCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,55 @@
namespace ArcaneLibs.Collections;

public class SemaphoreCache<T> where T : class {

internal readonly ConcurrentDictionary<string, T> Values = new();
internal readonly ConcurrentDictionary<string, SemaphoreSlim> Semaphores = new();

private readonly ConcurrentDictionary<string, T> _values = new();
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new();

public async Task<T> GetOrAdd(string key, Func<Task<T>> factory) {
ArgumentNullException.ThrowIfNull(key);
Semaphores.TryAdd(key, new SemaphoreSlim(1, 1));
await Semaphores[key].WaitAsync();
if (Values.TryGetValue(key, out var value)) {
Semaphores[key].Release();
_semaphores.TryAdd(key, new SemaphoreSlim(1, 1));
await _semaphores[key].WaitAsync();
if (_values.TryGetValue(key, out var value)) {
_semaphores[key].Release();
return value;
}

var val = await factory();
Values.TryAdd(key, val);
Semaphores[key].Release();
return val;
try {
var val = await factory();
_values.TryAdd(key, val);
return val;
}
finally {
_semaphores[key].Release();
}
}
}

public class ExpiringSemaphoreCache<T> : SemaphoreCache<T> where T : class {
public class ExpiringSemaphoreCache<T> where T : class {
private readonly ConcurrentDictionary<string, T> _values = new();
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new();
private readonly ConcurrentDictionary<string, DateTime> _expiry = new();

public async Task<T> GetOrAdd(string key, Func<Task<T>> factory, TimeSpan expiry) {
ArgumentNullException.ThrowIfNull(key);
Semaphores.TryAdd(key, new SemaphoreSlim(1, 1));
await Semaphores[key].WaitAsync();
if (Values.TryGetValue(key, out var value) && _expiry.TryGetValue(key, out var exp) && exp > DateTime.Now) {
Semaphores[key].Release();
_semaphores.TryAdd(key, new SemaphoreSlim(1, 1));
await _semaphores[key].WaitAsync();
if (_values.TryGetValue(key, out var value) && _expiry.TryGetValue(key, out var exp) && exp > DateTime.Now) {
_semaphores[key].Release();
return value;
}

var val = await factory();
Values.TryAdd(key, val);
_values.TryAdd(key, val);
_expiry.TryAdd(key, DateTime.Now + expiry);
Semaphores[key].Release();
_semaphores[key].Release();

#pragma warning disable CS4014 // We intentionally do not await this task - this handles cache expiry
Task.Delay(expiry).ContinueWith(__ => {
_values.TryRemove(key, out var _);
_semaphores.TryRemove(key, out var _);
});
#pragma warning restore CS4014

return val;
}
}
10 changes: 0 additions & 10 deletions ArcaneLibs/Extensions/CollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@ public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<Ta
yield return await task;
}
}

//return task results async without preserving order
public static async IAsyncEnumerable<(Task task, T result)> ToAsyncEnumerableWithContext<T>(this IEnumerable<Task<T>> tasks) {
var taskList = tasks.ToList();
while (taskList.Count > 0) {
var task = await Task.WhenAny(taskList);
taskList.Remove(task);
yield return (task, await task);
}
}

public static int GetWidth<T>(this T[,] array) => array.GetLength(1);
public static int GetHeight<T>(this T[,] array) => array.GetLength(0);
Expand Down
21 changes: 21 additions & 0 deletions ArcaneLibs/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,25 @@ public static byte[] ZlibDecompress(this IEnumerable<byte> bytes) {
}

public static T GetByCaseInsensitiveKey<T>(this IDictionary<string, T> dict, string key) => dict.First(x => x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase)).Value;

//return task results async without preserving order
public static async IAsyncEnumerable<(TK, TV)> ToAsyncEnumerable<TK, TV>(this Dictionary<TK, Task<TV>> tasks) where TK : notnull {
var taskList = tasks.ToDictionary();
while (taskList.Count > 0) {
var task = await Task.WhenAny(taskList.Values);
var result = taskList.First(x => x.Value == task);
taskList.Remove(result.Key);
yield return (result.Key, await task);
}
}

public static async IAsyncEnumerable<TK> ToAsyncEnumerable<TK>(this Dictionary<TK, Task> tasks) where TK : notnull {
var taskList = tasks.ToDictionary();
while (taskList.Count > 0) {
var task = await Task.WhenAny(taskList.Values);
var result = taskList.First(x => x.Value == task).Key;
taskList.Remove(result);
yield return result;
}
}
}

0 comments on commit 808f94b

Please sign in to comment.