From 12466796a350ad79b1a918dd11ec7d50498092d7 Mon Sep 17 00:00:00 2001 From: Olivier Giniaux Date: Fri, 6 Sep 2024 15:34:10 +0200 Subject: [PATCH] Add RoaringBitmap.ToArray() --- Equativ.RoaringBitmaps/RoaringArray.cs | 165 ++++++++++++------------ Equativ.RoaringBitmaps/RoaringBitmap.cs | 15 +++ Equativ.RoaringBitmaps/Utils.cs | 15 +-- 3 files changed, 103 insertions(+), 92 deletions(-) diff --git a/Equativ.RoaringBitmaps/RoaringArray.cs b/Equativ.RoaringBitmaps/RoaringArray.cs index 314932a..36cab19 100755 --- a/Equativ.RoaringBitmaps/RoaringArray.cs +++ b/Equativ.RoaringBitmaps/RoaringArray.cs @@ -11,32 +11,31 @@ internal class RoaringArray : IEnumerable, IEquatable private const int SerialCookieNoRuncontainer = 12346; private const int SerialCookie = 12347; private const int NoOffsetThreshold = 4; - private readonly ushort[] _mKeys; - private readonly int _mSize; - private readonly Container[] _mValues; + private readonly ushort[] _keys; + private readonly int _size; + private readonly Container[] _values; - // ReSharper disable once SuggestBaseTypeForParameter /// /// Use List directly, because the enumerator is a struct /// internal RoaringArray(int size, List keys, List containers) { - _mSize = size; - _mKeys = new ushort[_mSize]; - _mValues = new Container[_mSize]; - for (var i = 0; i < _mSize; i++) + _size = size; + _keys = new ushort[_size]; + _values = new Container[_size]; + for (var i = 0; i < _size; i++) { - _mKeys[i] = keys[i]; - _mValues[i] = containers[i]; - Cardinality += _mValues[i].Cardinality; + _keys[i] = keys[i]; + _values[i] = containers[i]; + Cardinality += _values[i].Cardinality; } } private RoaringArray(int size, ushort[] keys, Container[] containers) { - _mSize = size; - _mKeys = keys; - _mValues = containers; + _size = size; + _keys = keys; + _values = containers; for (var i = 0; i < containers.Length; i++) { Cardinality += containers[i].Cardinality; @@ -47,18 +46,18 @@ private RoaringArray(int size, ushort[] keys, Container[] containers) public IEnumerator GetEnumerator() { - for (var i = 0; i < _mSize; i++) + for (var i = 0; i < _size; i++) { - var key = _mKeys[i]; + var key = _keys[i]; var shiftedKey = key << 16; - var container = _mValues[i]; + var container = _values[i]; foreach (var @ushort in container) { yield return shiftedKey | @ushort; } } } - + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); @@ -74,13 +73,13 @@ public bool Equals(RoaringArray? other) { return false; } - if (_mSize != other._mSize) + if (_size != other._size) { return false; } - for (var i = 0; i < _mSize; i++) + for (var i = 0; i < _size; i++) { - if ((_mKeys[i] != other._mKeys[i]) || !_mValues[i].Equals(other._mValues[i])) + if ((_keys[i] != other._keys[i]) || !_values[i].Equals(other._values[i])) { return false; } @@ -90,13 +89,13 @@ public bool Equals(RoaringArray? other) private int AdvanceUntil(ushort key, int index) { - return Utils.AdvanceUntil(_mKeys, index, _mKeys.Length, key); + return Utils.AdvanceUntil(_keys, index, _keys.Length, key); } public static RoaringArray operator |(RoaringArray x, RoaringArray y) { - var xLength = x._mSize; - var yLength = y._mSize; + var xLength = x._size; + var yLength = y._size; var keys = new List(xLength + yLength); var containers = new List(xLength + yLength); var size = 0; @@ -104,14 +103,14 @@ private int AdvanceUntil(ushort key, int index) var yPos = 0; if ((xPos < xLength) && (yPos < yLength)) { - var xKey = x._mKeys[xPos]; - var yKey = y._mKeys[yPos]; + var xKey = x._keys[xPos]; + var yKey = y._keys[yPos]; while (true) { if (xKey == yKey) { keys.Add(xKey); - containers.Add(x._mValues[xPos] | y._mValues[yPos]); + containers.Add(x._values[xPos] | y._values[yPos]); size++; xPos++; yPos++; @@ -119,32 +118,32 @@ private int AdvanceUntil(ushort key, int index) { break; } - xKey = x._mKeys[xPos]; - yKey = y._mKeys[yPos]; + xKey = x._keys[xPos]; + yKey = y._keys[yPos]; } else if (xKey < yKey) { keys.Add(xKey); - containers.Add(x._mValues[xPos]); + containers.Add(x._values[xPos]); size++; xPos++; if (xPos == xLength) { break; } - xKey = x._mKeys[xPos]; + xKey = x._keys[xPos]; } else { keys.Add(yKey); - containers.Add(y._mValues[yPos]); + containers.Add(y._values[yPos]); size++; yPos++; if (yPos == yLength) { break; } - yKey = y._mKeys[yPos]; + yKey = y._keys[yPos]; } } } @@ -152,8 +151,8 @@ private int AdvanceUntil(ushort key, int index) { for (var i = yPos; i < yLength; i++) { - keys.Add(y._mKeys[i]); - containers.Add(y._mValues[i]); + keys.Add(y._keys[i]); + containers.Add(y._values[i]); size++; } } @@ -161,8 +160,8 @@ private int AdvanceUntil(ushort key, int index) { for (var i = xPos; i < xLength; i++) { - keys.Add(x._mKeys[i]); - containers.Add(x._mValues[i]); + keys.Add(x._keys[i]); + containers.Add(x._values[i]); size++; } } @@ -171,8 +170,8 @@ private int AdvanceUntil(ushort key, int index) public static RoaringArray operator &(RoaringArray x, RoaringArray y) { - var xLength = x._mSize; - var yLength = y._mSize; + var xLength = x._size; + var yLength = y._size; List? keys = null; List? containers = null; var size = 0; @@ -180,11 +179,11 @@ private int AdvanceUntil(ushort key, int index) var yPos = 0; while ((xPos < xLength) && (yPos < yLength)) { - var xKey = x._mKeys[xPos]; - var yKey = y._mKeys[yPos]; + var xKey = x._keys[xPos]; + var yKey = y._keys[yPos]; if (xKey == yKey) { - var c = x._mValues[xPos] & y._mValues[yPos]; + var c = x._values[xPos] & y._values[yPos]; if (c.Cardinality > 0) { if (keys == null) @@ -214,8 +213,8 @@ private int AdvanceUntil(ushort key, int index) public static RoaringArray operator ^(RoaringArray x, RoaringArray y) { - var xLength = x._mSize; - var yLength = y._mSize; + var xLength = x._size; + var yLength = y._size; var keys = new List(xLength + yLength); var containers = new List(xLength + yLength); var size = 0; @@ -223,14 +222,14 @@ private int AdvanceUntil(ushort key, int index) var yPos = 0; if ((xPos < xLength) && (yPos < yLength)) { - var xKey = x._mKeys[xPos]; - var yKey = y._mKeys[yPos]; + var xKey = x._keys[xPos]; + var yKey = y._keys[yPos]; while (true) { if (xKey == yKey) { keys.Add(xKey); - containers.Add(x._mValues[xPos] ^ y._mValues[yPos]); + containers.Add(x._values[xPos] ^ y._values[yPos]); size++; xPos++; yPos++; @@ -238,32 +237,32 @@ private int AdvanceUntil(ushort key, int index) { break; } - xKey = x._mKeys[xPos]; - yKey = y._mKeys[yPos]; + xKey = x._keys[xPos]; + yKey = y._keys[yPos]; } else if (xKey < yKey) { keys.Add(xKey); - containers.Add(x._mValues[xPos]); + containers.Add(x._values[xPos]); size++; xPos++; if (xPos == xLength) { break; } - xKey = x._mKeys[xPos]; + xKey = x._keys[xPos]; } else { keys.Add(yKey); - containers.Add(y._mValues[yPos]); + containers.Add(y._values[yPos]); size++; yPos++; if (yPos == yLength) { break; } - yKey = y._mKeys[yPos]; + yKey = y._keys[yPos]; } } } @@ -271,8 +270,8 @@ private int AdvanceUntil(ushort key, int index) { for (var i = yPos; i < yLength; i++) { - keys.Add(y._mKeys[i]); - containers.Add(y._mValues[i]); + keys.Add(y._keys[i]); + containers.Add(y._values[i]); size++; } } @@ -280,8 +279,8 @@ private int AdvanceUntil(ushort key, int index) { for (var i = xPos; i < xLength; i++) { - keys.Add(x._mKeys[i]); - containers.Add(x._mValues[i]); + keys.Add(x._keys[i]); + containers.Add(x._values[i]); size++; } } @@ -297,7 +296,7 @@ private int AdvanceUntil(ushort key, int index) for (var i = 0; i < Container.MaxCapacity; i++) { var ushortI = (ushort) i; - var index = Array.BinarySearch(x._mKeys, oldIndex, x._mSize - oldIndex, ushortI); + var index = Array.BinarySearch(x._keys, oldIndex, x._size - oldIndex, ushortI); if (index < 0) { keys.Add(ushortI); @@ -306,7 +305,7 @@ private int AdvanceUntil(ushort key, int index) } else { - var c = x._mValues[index]; + var c = x._values[index]; if (!c.Equals(BitmapContainer.One)) // the bitwise negation of the one container is the zero container { var nc = ~c; @@ -325,8 +324,8 @@ private int AdvanceUntil(ushort key, int index) public static RoaringArray AndNot(RoaringArray x, RoaringArray y) { - var xLength = x._mSize; - var yLength = y._mSize; + var xLength = x._size; + var yLength = y._size; var keys = new List(xLength); var containers = new List(xLength); var size = 0; @@ -334,11 +333,11 @@ public static RoaringArray AndNot(RoaringArray x, RoaringArray y) var yPos = 0; while ((xPos < xLength) && (yPos < yLength)) { - var xKey = x._mKeys[xPos]; - var yKey = y._mKeys[yPos]; + var xKey = x._keys[xPos]; + var yKey = y._keys[yPos]; if (xKey == yKey) { - var c = Container.AndNot(x._mValues[xPos], y._mValues[yPos]); + var c = Container.AndNot(x._values[xPos], y._values[yPos]); if (c.Cardinality > 0) { keys.Add(xKey); @@ -353,8 +352,8 @@ public static RoaringArray AndNot(RoaringArray x, RoaringArray y) var next = x.AdvanceUntil(yKey, xPos); for (var i = xPos; i < next; i++) { - keys.Add(x._mKeys[i]); - containers.Add(x._mValues[i]); + keys.Add(x._keys[i]); + containers.Add(x._values[i]); size++; } xPos = next; @@ -368,8 +367,8 @@ public static RoaringArray AndNot(RoaringArray x, RoaringArray y) { for (var i = xPos; i < xLength; i++) { - keys.Add(x._mKeys[i]); - containers.Add(x._mValues[i]); + keys.Add(x._keys[i]); + containers.Add(x._values[i]); size++; } } @@ -387,11 +386,11 @@ public override int GetHashCode() unchecked { var code = 17; - code = code * 23 + _mSize; - for (var i = 0; i < _mSize; i++) + code = code * 23 + _size; + for (var i = 0; i < _size; i++) { - code = code * 23 + _mKeys[i].GetHashCode(); - code = code * 23 + _mValues[i].GetHashCode(); + code = code * 23 + _keys[i].GetHashCode(); + code = code * 23 + _values[i].GetHashCode(); } return code; } @@ -402,9 +401,9 @@ public static void Serialize(RoaringArray roaringArray, Stream stream) var hasRun = HasRunContainer(roaringArray); using (var binaryWriter = new BinaryWriter(stream, Encoding.UTF8, true)) { - var size = roaringArray._mSize; - var keys = roaringArray._mKeys; - var values = roaringArray._mValues; + var size = roaringArray._size; + var keys = roaringArray._keys; + var values = roaringArray._values; var startOffset = 0; if (hasRun) { @@ -476,9 +475,9 @@ public static void Serialize(RoaringArray roaringArray, Stream stream) private static bool HasRunContainer(RoaringArray roaringArray) { - for (var i = 0; i < roaringArray._mSize; i++) + for (var i = 0; i < roaringArray._size; i++) { - if (roaringArray._mValues[i].Equals(ArrayContainer.One) || roaringArray._mValues[i].Equals(BitmapContainer.One)) + if (roaringArray._values[i].Equals(ArrayContainer.One) || roaringArray._values[i].Equals(BitmapContainer.One)) { return true; } @@ -592,12 +591,12 @@ public static RoaringArray Deserialize(Stream stream) public static RoaringArray Optimize(RoaringArray roaringArray) { - var keys = new ushort[roaringArray._mSize]; - Array.Copy(roaringArray._mKeys, keys, roaringArray._mSize); - var containers = new Container[roaringArray._mSize]; - for (var i = 0; i < roaringArray._mSize; i++) + var keys = new ushort[roaringArray._size]; + Array.Copy(roaringArray._keys, keys, roaringArray._size); + var containers = new Container[roaringArray._size]; + for (var i = 0; i < roaringArray._size; i++) { - var currentContainer = roaringArray._mValues[i]; + var currentContainer = roaringArray._values[i]; if (currentContainer.Equals(ArrayContainer.One)) { containers[i] = ArrayContainer.One; @@ -611,6 +610,6 @@ public static RoaringArray Optimize(RoaringArray roaringArray) containers[i] = currentContainer; } } - return new RoaringArray(roaringArray._mSize, keys, containers); + return new RoaringArray(roaringArray._size, keys, containers); } } \ No newline at end of file diff --git a/Equativ.RoaringBitmaps/RoaringBitmap.cs b/Equativ.RoaringBitmaps/RoaringBitmap.cs index 32fe3c7..f76fb8f 100755 --- a/Equativ.RoaringBitmaps/RoaringBitmap.cs +++ b/Equativ.RoaringBitmaps/RoaringBitmap.cs @@ -26,6 +26,21 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + /// + /// Convert the bitmap to an array of integers + /// + /// Array of integers + public int[] ToArray() + { + var array = new int[Cardinality]; + var pos = 0; + foreach (var i in this) + { + array[pos++] = i; + } + return array; + } public bool Equals(RoaringBitmap other) { diff --git a/Equativ.RoaringBitmaps/Utils.cs b/Equativ.RoaringBitmaps/Utils.cs index 3649f03..8bb6d39 100755 --- a/Equativ.RoaringBitmaps/Utils.cs +++ b/Equativ.RoaringBitmaps/Utils.cs @@ -1,13 +1,11 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; namespace Equativ.RoaringBitmaps; -/// -/// Pretty much everything in here are straight conversions from the original Util class in the java Roaring Bitmap project. -/// -public static class Utils +internal static class Utils { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int Popcnt(ulong[] longs) @@ -16,11 +14,10 @@ internal static int Popcnt(ulong[] longs) { return (int)PopcntNeon.Popcnt(longs.AsSpan()); } - // AVX2 Support needs proper testing before being enabled - // if (Avx2.IsSupported) - // { - // return (int)PopcntAvx2.Popcnt(longs.AsSpan()); - // } + if (Avx2.IsSupported) + { + return (int)PopcntAvx2.Popcnt(longs.AsSpan()); + } // AVX512 Support needs proper testing before being enabled // if (Avx512BW.IsSupported) // {