Gapotchenko.FX.Collections
2024.1.3
Prefix Reserved
dotnet add package Gapotchenko.FX.Collections --version 2024.1.3
NuGet\Install-Package Gapotchenko.FX.Collections -Version 2024.1.3
<PackageReference Include="Gapotchenko.FX.Collections" Version="2024.1.3" />
paket add Gapotchenko.FX.Collections --version 2024.1.3
#r "nuget: Gapotchenko.FX.Collections, 2024.1.3"
// Install Gapotchenko.FX.Collections as a Cake Addin #addin nuget:?package=Gapotchenko.FX.Collections&version=2024.1.3 // Install Gapotchenko.FX.Collections as a Cake Tool #tool nuget:?package=Gapotchenko.FX.Collections&version=2024.1.3
Overview
The module was started by borrowing an implementation of ConcurrentHashSet<T>
from Mr. Bar Arnon.
Other than that, the module provides polyfills for missing functionality in .NET.
Collections
ConcurrentHashSet<T>
ConcurrentHashSet<T>
provided by Gapotchenko.FX.Collections
is a thread-safe implementation of HashSet<T>
.
AssociativeArray<TKey, TValue>
AssociativeArray<TKey, TValue>
provided by Gapotchenko.FX.Collections
is a drop-in replacement for Dictionary<TKey, TValue>
that can handle null
keys.
Dictionary<TKey, TValue>
cannot work with null
keys and throws ArgumentNullException
whenever a null
key is encountered.
AssociativeArray<TKey, TValue>
resolves that by supporting a full space of keys without opinionated exclusions.
Deque<T>
Deque<T>
provided by Gapotchenko.FX.Collections
is a linear collection that supports element insertion and removal at both ends with O(1) algorithmic complexity.
Deque<T>
can be seen as a List<T>
, but in contrast to the List<T>
, both ends of the collection support efficient addition and removal of elements.
Collection Construction Kits
A concept of a construction kit provided by Gapotchenko.FX.Collections
module allows you to quickly and reliably build customized collection primitives.
<details> <summary>More information</summary>
ISet<T> Construction Kit
For example, let's imagine that we need to build a custom implementation of System.Collections.Generic.ISet<T>
collection.
In order to do that, we need to implement a plethora of methods such as UnionWith
, IntersectWith
, ExceptWith
and others just to begin with.
It gets complicated and nuanced quickly, while all we want is to build a simple custom ISet<T>
implementation.
This is where the concept of a construction kit starts to shine.
In our case, instead of implementing ISet<T>
interface directly, we just derive our implementation from the one provided by the corresponding construction kit:
using Gapotchenko.FX.Collections.Generic.Kits;
using Gapotchenko.FX.Linq;
using System.Collections;
class MyBitSet(int capacity) : SetKit<int>
{
public override bool Contains(int item) => m_Bits[item];
public override bool Add(int item) => ChangeBit(item, true);
public override bool Remove(int item) => ChangeBit(item, false);
bool ChangeBit(int item, bool value)
{
if (m_Bits[item] != value)
{
m_Bits[item] = value;
if (value)
++m_CachedCount;
else
--m_CachedCount;
return true;
}
else
{
return false;
}
}
public override void Clear()
{
m_Bits.SetAll(false);
m_CachedCount = 0;
}
public override int Count => m_CachedCount ??= this.Stream().Count();
int? m_CachedCount = 0;
public override IEnumerator<int> GetEnumerator()
{
for (int i = 0, n = m_Bits.Count; i < n; ++i)
if (m_Bits[i])
yield return i;
}
protected BitArray Bits
{
get => m_Bits;
set { m_Bits = value; m_CachedCount = null; }
}
BitArray m_Bits = new(capacity);
}
We implemented just several abstract methods and got a fully functional and compliant ISet<T>
collection.
All the remaining implementation details are covered by the construction kit our class is derived from.
Mind you, a generic implementation does not mean inefficient. If we have a more optimized way to do some operations, we just override the corresponding methods:
class MyHWAcceleratedBitSet(int capacity) : MyBitSet(capacity)
{
public override bool Overlaps(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
return Bits.And(bitSet.Bits).HasAnySet();
else
return base.Overlaps(other);
}
public override void IntersectWith(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
Bits = Bits.And(bitSet.Bits);
else
base.IntersectWith(other);
}
public override void UnionWith(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
Bits = Bits.Or(bitSet.Bits);
else
base.UnionWith(other);
}
public override void ExceptWith(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
Bits = Bits.And(bitSet.Bits.Not());
else
base.ExceptWith(other);
}
public override void SymmetricExceptWith(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
Bits = Bits.Xor(bitSet.Bits);
else
base.SymmetricExceptWith(other);
}
public override bool SetEquals(IEnumerable<int> other)
{
if (other is MyBitSet bitSet)
return bitSet.Bits.Xor(bitSet.Bits).HasAnySet();
else
return base.SetEquals(other);
}
}
Given that BitArray
operations are hardware-accelerated in all modern .NET versions,
it quickly boils from a generic ISet<T>
implementation down to a highly-optimized one, leveraging AVX and SSE vector instructions provided by CPU.
What a ride just within a screen of code.
</details>
Polyfills
AddRange<T>(IEnumerable<T>) for Collections
AddRange
is a frequently used operation that allows you to add a sequence of elements to the end of a collection.
Like this:
using Gapotchenko.FX.Collections.Generic;
var collection = new Collection<int>();
…
collection.AddRange(numbers.Where(x => x % 2 == 0)); // add even numbers
<details> <summary>Other polyfills</summary>
KeyValuePair Polyfill
.NET provides a versatile KeyValuePair<TKey, TValue>
struct and suggests a default way for its instantiation:
new KeyValuePair<TKey, TValue>(key, value)
Which is, well, not handy as it often comes to this:
new KeyValuePair<BindingManagerDataErrorEventHandler, ICom2PropertyPageDisplayService>(key, value)
Gapotchenko.FX.Collections
provides a better way to instantiate a KeyValuePair<TKey, TValue>
struct:
using Gapotchenko.FX.Collections.Generic;
KeyValuePair.Create(key, value)
It leverages the automatic type inference provided by some .NET languages like C#.
Deconstruction
Gapotchenko.FX.Collections
module comes with a function for KeyValuePair<TKey, TValue>
deconstruction, so you can write this:
using Gapotchenko.FX.Collections.Generic;
void ProcessMap(IDictionary<string, int> map)
{
foreach (var (key, value) in map)
{
…
}
}
instead of a more verbose variant:
void ProcessMap(IDictionary<string, int> map)
{
foreach (var i in map)
{
var key = i.Key;
var value = i.Value;
…
}
}
A little detail, but sometimes it matters a lot when you are amid the heat of the code.
PriorityQueue Polyfill
PriorityQueue<TElement, TPriority>
provided by Gapotchenko.FX.Collections
module is an implementation of the prioritized queue available in .NET 6.0+.
The polyfill makes it available to all other supported .NET versions.
</details>
Commonly Used Types
Gapotchenko.FX.Collections.Concurrent.ConcurrentHashSet<T>
Gapotchenko.FX.Collections.Generic.AssociativeArray<T>
Other Modules
Let's continue with a look at some other modules provided by Gapotchenko.FX:
- Gapotchenko.FX
- Gapotchenko.FX.AppModel.Information
- ➴ Gapotchenko.FX.Collections
- Gapotchenko.FX.Console
- Gapotchenko.FX.Data
- Gapotchenko.FX.Diagnostics
- Gapotchenko.FX.IO
- Gapotchenko.FX.Linq
- Gapotchenko.FX.Math
- Gapotchenko.FX.Memory
- Gapotchenko.FX.Security.Cryptography
- Gapotchenko.FX.Text
- Gapotchenko.FX.Threading
- Gapotchenko.FX.Tuples
Or look at the full list of modules.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 is compatible. netcoreapp2.2 was computed. netcoreapp3.0 is compatible. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 is compatible. net472 is compatible. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 2.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
.NETCoreApp 3.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
.NETFramework 4.6.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
- System.ValueTuple (>= 4.5.0)
-
.NETFramework 4.7.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
.NETFramework 4.7.2
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
.NETStandard 2.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
.NETStandard 2.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
net5.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
net6.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
net7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
net8.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
-
net9.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Linq (>= 2024.1.3)
NuGet packages (7)
Showing the top 5 NuGet packages that depend on Gapotchenko.FX.Collections:
Package | Downloads |
---|---|
Gapotchenko.FX.Threading
Provides complementary primitives for multithreaded and asynchronous programming in .NET. |
|
Gapotchenko.FX.Profiles.Core
Represents the Core profile of Gapotchenko.FX. |
|
Gapotchenko.FX.Math.Geometry
The module provides primitives and operations for geometry math. |
|
Gapotchenko.FX.Math.Combinatorics
Provides math operations for combinatorics. |
|
Gapotchenko.FX.Math.Topology
The module provides data structures and primitives for working with abstract topologies. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2024.1.3 | 441 | 11/10/2024 |
2022.2.7 | 1,717 | 5/1/2022 |
2022.2.5 | 1,493 | 5/1/2022 |
2022.1.4 | 1,498 | 4/6/2022 |
2021.2.21 | 1,576 | 1/21/2022 |
2021.2.20 | 1,535 | 1/17/2022 |
2021.1.5 | 816 | 7/6/2021 |
2020.2.2-beta | 396 | 11/21/2020 |
2020.1.15 | 727 | 11/5/2020 |
2020.1.9-beta | 487 | 7/14/2020 |
2020.1.8-beta | 466 | 7/14/2020 |
2020.1.7-beta | 518 | 7/14/2020 |
2020.1.1-beta | 540 | 2/11/2020 |
2019.3.7 | 804 | 11/4/2019 |
2019.2.20 | 777 | 8/13/2019 |
2019.1.151 | 848 | 3/30/2019 |