Add extension methods to simplify alternate lookup for `ReadOnlySpan<char>` on `ISet<T>`
- Dominant language
- C#
- Stars
- 2.4k
- Forks
- 658
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 9
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Task description
Now that J2N has alternate lookup functionality implemented, we can utilize it to make extension methods that make syntax seamless when converting values from `string` to `ReadOnlySpan`. For now, let's keep the implementation minimal and expand it as needed. There are a few APIs that we will almost certainly need that we can implement now to set a precedent for any others that may be added later, as needed.
### Proposed API
```c#
namespace Lucene.Net.Support
{
internal static class DictionaryExtensions
{
public static bool TryAdd(this IDictionary dictionary, ReadOnlySpan key, TValue value);
public static bool ContainsKey(this IDictionary dictionary, ReadOnlySpan key);
public static bool TryGetValue(this IDictionary dictionary, ReadOnlySpan key, [MaybeNullWhen(false)] out TValue value);
public static bool TryGetValue(ReadOnlySpan key, [MaybeNullWhen(false)] out TKey actualKey, [MaybeNullWhen(false)] out TValue value);
public static TValue Put(this IDictionary dictionary, ReadOnlySpan key, TValue value);
public static bool Remove(this IDictionary dictionary, ReadOnlySpan key);
}
internal static class SetExtensions
{
public static bool Add(this ISet set, ReadOnlySpan item);
public static bool Contains(this ISet set, ReadOnlySpan item);
public static bool TryGetValue(this ISet set, ReadOnlySpan equalValue, [MaybeNullWhen(false)] out T actualValue);
public static bool Remove(this ISet set, ReadOnlySpan item);
}
}
```
Note that these interface overloads will be used in many situations because Lucene.NET primarily passes interfaces, however, we can also include overloads for
- `JCG.Dictionary`
- `JCG.OrderedDictionary`
- `JCG.SortedDictionary`
- `JCG.HashSet`
- `JCG.OrderedHashSet`
- `JCG.SortedSet`
This would rely on the compiler for direct calls in many cases, which would save a lot of type comparison overhead for those callers.
We can also include BCL types in target frameworks that support alternate lookup, but we probably should just include those optimizations in the `IDictionary` and `ISet` implementations rather than going through the effort to make extra overloads.
We should also optimize the existing `Put()` extension method to use `CollectionMarshal/CollectionsMarshal` where supported, since it will eliminate an extra lookup from our current implementation (which does 2 lookups).
The interface overloads should fall back to using a collection scan for small collections or a key allocation for large collections over 64 elements. We should also put `Debugging.Assert()` calls just before the slow path so we don't accidentally call it in any of the code that we ship. Now that we have low-level collection implementations (except for `ConcurrentDictionary`), we should be using them exclusively.
Contributor guide
Assessment
This issue has not been assessed yet.