Standard collections with some optimizations.
Rist<T>
— recyclable indexed collection.
Implementation is based on List<T>, but uses pooling for the internal array.
using Misnomer;
using Misnomer.Extensions;
using Rist<string> rist = Directory.EnumerateDirectories(".").ToRist();
rist.AddRange(Directory.EnumerateFiles("."));
foreach (string item in rist)
Console.WriteLine(item);
string[] array = rist.MoveToArray(out int count);
int length = array.Length;
Debug.Assert(count <= length);
Console.WriteLine($"{nameof(count)}: {count}, {nameof(length)}: {length}");
It is not a fatal error to not dispose an instance of Rist<T>
.
Failure to do so just leads to not returning the internal array to the pool, so it may be not worth to introduce nested scope with using
block.
Implementation deliberately prefers shared pool over private one for the sake of performance.
The risk is that untrusted caller can hold a reference to an array after returning it to ArrayPool<T>.Shared, thus getting access to internal state of Rist<T>
on subsequent use.
Fictionary<TKey, TValue, TKeyComparer>
— fast associative collection.
Implementation is based on Dictionary<TKey, TValue>, but uses generic parameter constraint for polymorphic key comparer.
Specializing with concrete type instead of indirect call to IEqualityComparer<TKey> interface allows to avoid virtual call and prevents from boxing in case of value types.
using Misnomer;
using Misnomer.Extensions;
IEnumerable<FileInfo> currentDirFiles =
new DirectoryInfo(Environment.CurrentDirectory).EnumerateFiles();
using Fictionary<string, FileInfo, OrdinalStringComparer> fictionary = currentDirFiles
.ToFictionary(fi => fi.Name, new OrdinalStringComparer());
IEnumerable<FileInfo> userDirFiles =
new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)).EnumerateFiles();
foreach (FileInfo fi in userDirFiles)
fictionary.TryAdd(fi.Name, fi);
foreach (KeyValuePair<string, FileInfo> kv in fictionary)
Console.WriteLine($"{kv.Key}\t{kv.Value.Directory.FullName}");
Console.WriteLine();
if (fictionary.TryGetValue(".gitconfig", out FileInfo? value))
Console.WriteLine($"{value.Name}: {value.Length} bytes");
There are several ways to create instance of Fictionary<TKey, TValue, TKeyComparer>
.
Constructor overloads are similar to those of Dictionary<TKey, TValue>
, but explicitly require passing comparer and specifying all types, so can be verbose.
To utilize type inference for comparer, you can use factory methods defined in Fictionary<TKey, TValue>
static class:
using var f = Fictionary<string, int>.Create(comparer: new OrdinalStringComparer());
Inferred type for f
here is Fictionary<string, int, OrdinalStringComparer>
.
There are less generic parameters to specify comparing to invoking constructor:
using Fictionary<string, int, OrdinalStringComparer> f = new(comparer: new OrdinalStringComparer());
In case if TKey
implements IEquatable<TKey>
, and you're fine with this default comparison, you can use factory methods defined in DefaultFictionary<TKey, TValue>
static class:
using var f = DefaultFictionary<int, string>.Create(capacity: 23);
Inferred type for f
here is Fictionary<int, string, GenericEqualityComparer<int>>
.
GenericEqualityComparer<T>
is like EqualityComparer<T>, but requires type of comparands to implement IEquatable<TKey>
. Unlike EqualityComparer<T>
it will never fall back to Object.Equals(Object)
, so no unexpected boxing may happen.
In case if you want to initialize dictionary from collection, you can use ToFictionary()
extension methods; just import Misnomer.Extensions
namespace:
using var f = Directory.EnumerateDirectories(".")
.ToFictionary(s => s, s => new DirectoryInfo(s), new OrdinalStringComparer());
Take a look at reports in benchmarks/ directory. Or even better, measure performance by yourself on your environment.
For example for string
keys Fictionary<string, int, TComparer>
shows better performance than Dictionary<string, int>
when TCmparer
is value type.
If comparer is of reference type then outcome may vary depending on JIT/platform/runtime combination.
All libraries support Source Link for source code debugging. To enable stepping into library methods implementation in Visual Studio 2017 Update 9, select Enable Source Link support in debugging options, and clear Enable Just My Code. Source code will be automatically downloaded from GitHub on demand.
The icon is designed by OpenMoji — the open-source emoji and icon project. License: CC BY-SA 4.0.