Skip to content

Commit 4aa17d1

Browse files
authored
Add params ReadOnlySpan overloads (#606)
* Add `params ReadOnlySpan` overloads * Split a special overload `ToFastArray` for array
1 parent 0a1043f commit 4aa17d1

File tree

5 files changed

+125
-36
lines changed

5 files changed

+125
-36
lines changed

src/core/StackExchange.Redis.Extensions.Core/Abstractions/IRedisDatabase.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ Task<bool> SetContainsAsync<T>(string key, T item, CommandFlags flag = CommandFl
274274
/// <param name="items">Name of the member.</param>
275275
Task<long> SetAddAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params T[] items);
276276

277+
/// <summary>
278+
/// Run SADD command http://redis.io/commands/sadd
279+
/// </summary>
280+
/// <typeparam name="T">The type of the expected object.</typeparam>
281+
/// <param name="key">The cache key.</param>
282+
/// <param name="flag">Behaviour markers associated with a given command</param>
283+
/// <param name="items">Name of the member.</param>
284+
Task<long> SetAddAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params ReadOnlySpan<T> items);
285+
277286
/// <summary>
278287
/// Run SREM command http://redis.io/commands/srem"
279288
/// </summary>
@@ -292,6 +301,15 @@ Task<bool> SetContainsAsync<T>(string key, T item, CommandFlags flag = CommandFl
292301
/// <param name="items">The items to store into Redis.</param>
293302
Task<long> SetRemoveAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params T[] items);
294303

304+
/// <summary>
305+
/// Run SREM command http://redis.io/commands/srem
306+
/// </summary>
307+
/// <typeparam name="T">The type of the expected object.</typeparam>
308+
/// <param name="key">The cache key.</param>
309+
/// <param name="flag">Behaviour markers associated with a given command</param>
310+
/// <param name="items">The items to store into Redis.</param>
311+
Task<long> SetRemoveAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params ReadOnlySpan<T> items);
312+
295313
/// <summary>
296314
/// Run SMEMBERS command see http://redis.io/commands/SMEMBERS
297315
/// </summary>

src/core/StackExchange.Redis.Extensions.Core/Extensions/SpanExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,28 @@ public static void EnumerateLines(this ReadOnlySpan<char> span, ref List<InfoDet
4747
}
4848
}
4949
}
50+
51+
public static bool Any<T>(this ReadOnlySpan<T> span, Predicate<T> condition)
52+
{
53+
for (var i = 0; i < span.Length; i++)
54+
{
55+
if (condition(span[i]))
56+
return true;
57+
}
58+
59+
return false;
60+
}
61+
62+
public static TResult[] ToFastArray<TSource, TResult>(this ReadOnlySpan<TSource> span, Func<TSource, TResult> action)
63+
{
64+
if (span.IsEmpty)
65+
return [];
66+
67+
var result = new TResult[span.Length];
68+
69+
for (var i = 0; i < span.Length; i++)
70+
result[i] = action.Invoke(span[i]);
71+
72+
return result;
73+
}
5074
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
using StackExchange.Redis.Extensions.Core.Extensions;
5+
6+
namespace StackExchange.Redis.Extensions.Core.Helpers;
7+
internal static class ExceptionThrowHelper
8+
{
9+
public static void ThrowIfSpanEmpty<T>(ReadOnlySpan<T> argument, string paramName)
10+
{
11+
if (argument.IsEmpty)
12+
throw new ArgumentException("The argument cannot be empty.", paramName);
13+
}
14+
15+
public static void ThrowIfExistsNullElement<T>(ReadOnlySpan<T> argument, string paramName)
16+
{
17+
if (argument.Any(x => x is null))
18+
ThrowNullElementException(paramName);
19+
}
20+
21+
[DoesNotReturn]
22+
private static void ThrowNullElementException(string? paramName)
23+
{
24+
throw new ArgumentException("items cannot contains any null item.", paramName);
25+
}
26+
}

src/core/StackExchange.Redis.Extensions.Core/Helpers/RedisKeyHelper.cs

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,46 +31,33 @@ public static void FastIteration<TSource>(this ICollection<TSource>? request, Ac
3131
}
3232
}
3333

34-
public static TResult[] ToFastArray<TSource, TResult>(this ICollection<TSource>? request, Func<TSource, TResult> action)
34+
public static TResult[] ToFastArray<TSource, TResult>(this TSource[]? source, Func<TSource, TResult> action)
3535
{
36-
if (request == null)
36+
if (source is not { Length: > 0 })
3737
return [];
3838

39-
var result = new TResult[request.Count];
39+
var result = new TResult[source.Length];
40+
for (var i = 0; i < source.Length; i++)
41+
result[i] = action.Invoke(source[i]);
4042

41-
if (request is TSource[] sourceArray)
42-
{
43-
ref var searchSpace = ref MemoryMarshal.GetReference(sourceArray.AsSpan());
44-
45-
for (var i = 0; i < sourceArray.Length; i++)
46-
{
47-
ref var r = ref Unsafe.Add(ref searchSpace, i);
48-
49-
result[i] = action.Invoke(r);
50-
}
51-
}
52-
/*
53-
54-
This could be helpful when we drop old frameworks
43+
return result;
44+
}
5545

56-
else if (request is List<TSource> sourceList)
57-
{
58-
var span = CollectionsMarshal.AsSpan(sourceList);
59-
ref var searchSpace = ref MemoryMarshal.GetReference(span);
46+
public static TResult[] ToFastArray<TSource, TResult>(this ICollection<TSource>? source, Func<TSource, TResult> action)
47+
{
48+
if (source is null)
49+
return [];
6050

61-
for (var i = 0; i < span.Length; i++)
62-
{
63-
ref var r = ref Unsafe.Add(ref searchSpace, i);
51+
var srcCnt = source.Count;
52+
if (srcCnt == 0)
53+
return [];
6454

65-
result[i] = action.Invoke(r);
66-
}
67-
}
68-
*/
69-
else
55+
var result = new TResult[srcCnt];
56+
var i = 0;
57+
foreach (var item in source)
7058
{
71-
var i = 0;
72-
foreach (var r in request)
73-
result[i++] = action.Invoke(r);
59+
result[i] = action.Invoke(item);
60+
i++;
7461
}
7562

7663
return result;

src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisDatabase.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,27 @@ public Task<long> SetAddAllAsync<T>(string key, CommandFlags flag = CommandFlags
323323
if (items == null)
324324
throw new ArgumentNullException(nameof(items), "items cannot be null.");
325325

326-
if (items.Any(item => item == null))
327-
throw new ArgumentException("items cannot contains any null item.", nameof(items));
326+
ExceptionThrowHelper.ThrowIfExistsNullElement(items, nameof(items));
327+
328+
var values = items.ToFastArray(item => (RedisValue)Serializer.Serialize(item));
329+
330+
return Database
331+
.SetAddAsync(
332+
key,
333+
values,
334+
flag);
335+
}
336+
337+
/// <inheritdoc/>
338+
public Task<long> SetAddAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params ReadOnlySpan<T> items)
339+
{
340+
#if NET8_0_OR_GREATER
341+
ArgumentException.ThrowIfNullOrEmpty(key);
342+
#else
343+
if (string.IsNullOrEmpty(key))
344+
throw new ArgumentException("key cannot be empty.", nameof(key));
345+
#endif
346+
ExceptionThrowHelper.ThrowIfExistsNullElement(items, nameof(items));
328347

329348
var values = items.ToFastArray(item => (RedisValue)Serializer.Serialize(item));
330349

@@ -358,8 +377,23 @@ public Task<long> SetRemoveAllAsync<T>(string key, CommandFlags flag = CommandFl
358377
if (items == null)
359378
throw new ArgumentNullException(nameof(items), "items cannot be null.");
360379

361-
if (items.Any(item => item == null))
362-
throw new ArgumentException("items cannot contains any null item.", nameof(items));
380+
ExceptionThrowHelper.ThrowIfExistsNullElement(items, nameof(items));
381+
382+
var values = items.ToFastArray(item => (RedisValue)Serializer.Serialize(item));
383+
384+
return Database.SetRemoveAsync(key, values, flag);
385+
}
386+
387+
/// <inheritdoc/>
388+
public Task<long> SetRemoveAllAsync<T>(string key, CommandFlags flag = CommandFlags.None, params ReadOnlySpan<T> items)
389+
{
390+
#if NET8_0_OR_GREATER
391+
ArgumentException.ThrowIfNullOrEmpty(key);
392+
#else
393+
if (string.IsNullOrEmpty(key))
394+
throw new ArgumentException("key cannot be empty.", nameof(key));
395+
#endif
396+
ExceptionThrowHelper.ThrowIfExistsNullElement(items, nameof(items));
363397

364398
var values = items.ToFastArray(item => (RedisValue)Serializer.Serialize(item));
365399

0 commit comments

Comments
 (0)