From 2c18b25f79ab1de5c51400f27b2ec1777613b118 Mon Sep 17 00:00:00 2001 From: Menaver Date: Wed, 22 May 2024 17:42:31 +0200 Subject: [PATCH] boost shift performance (#40) Co-authored-by: Dima Kileyko --- ...SetBitwiseShiftOverBigDataPerfTestSuit.cs} | 2 +- ...etBitwiseShiftOverSmallDataPerfTestSuit.cs | 67 ++++++ .../Properties/launchSettings.json | 8 +- .../NetBitSetMethodBitWiseTests.cs | 200 +++++++++++++++++ .../NetBitSetMethodConvertNegativeTests.cs | 207 ------------------ .../Internals/BitArrayConverter.cs | 11 - .../Menaver.NetBitSet.csproj | 6 +- .../NetBitSet.Methods.Bitwise.cs | 206 ++++++++++++++--- .../NetBitSet.Methods.Converts.cs | 9 - 9 files changed, 451 insertions(+), 265 deletions(-) rename src/Menaver.NetBitSet.Tests.Perf/Bitwise/{NetBitSetBitwiseShiftPerfTestSuit.cs => NetBitSetBitwiseShiftOverBigDataPerfTestSuit.cs} (94%) create mode 100644 src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverSmallDataPerfTestSuit.cs delete mode 100644 src/Menaver.NetBitSet.Tests/NetBitSetMethodConvertNegativeTests.cs diff --git a/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftPerfTestSuit.cs b/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverBigDataPerfTestSuit.cs similarity index 94% rename from src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftPerfTestSuit.cs rename to src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverBigDataPerfTestSuit.cs index d5fde2d..310a360 100644 --- a/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftPerfTestSuit.cs +++ b/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverBigDataPerfTestSuit.cs @@ -2,7 +2,7 @@ namespace Menaver.NetBitSet.Tests.Perf.Bitwise; -public class NetBitSetBitwiseShiftPerfTestSuit : PerfTestSuitBase +public class NetBitSetBitwiseShiftOverBigDataPerfTestSuit : PerfTestSuitBase { private const int ShiftCount = 3; diff --git a/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverSmallDataPerfTestSuit.cs b/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverSmallDataPerfTestSuit.cs new file mode 100644 index 0000000..f148e5a --- /dev/null +++ b/src/Menaver.NetBitSet.Tests.Perf/Bitwise/NetBitSetBitwiseShiftOverSmallDataPerfTestSuit.cs @@ -0,0 +1,67 @@ +using BenchmarkDotNet.Attributes; + +namespace Menaver.NetBitSet.Tests.Perf.Bitwise; + +public class NetBitSetBitwiseShiftOverSmallDataPerfTestSuit : PerfTestSuitBase +{ + private const int ShiftCount = 10000000; + + private NetBitSet _netBitSet = null!; + + // 1 byte, 2 bytes, 4 bytes, 8 bytes, 16 bytes + [Params(8, 16, 32, 64, 128)] public ulong BitCount; + + [IterationSetup] + public void Setup() + { + _netBitSet = BuildRandomNetBitSet(BitCount); + } + + [Benchmark] + public void ShiftLeft() + { + _netBitSet.ShiftLeft(ShiftCount, Bit.True); + } + + [Benchmark] + public void ShiftRight() + { + _netBitSet.ShiftRight(ShiftCount, Bit.True); + } + + [Benchmark] + public void ArithmeticShiftLeft() + { + _netBitSet.ArithmeticShiftLeft(ShiftCount); + } + + [Benchmark] + public void ArithmeticShiftRight() + { + _netBitSet.ArithmeticShiftRight(ShiftCount); + } + + [Benchmark] + public void LogicalShiftLeft() + { + _netBitSet.LogicalShiftLeft(ShiftCount); + } + + [Benchmark] + public void LogicalShiftRight() + { + _netBitSet.LogicalShiftRight(ShiftCount); + } + + [Benchmark] + public void CircularShiftLeft() + { + _netBitSet.CircularShiftLeft(ShiftCount); + } + + [Benchmark] + public void CircularShiftRight() + { + _netBitSet.CircularShiftRight(ShiftCount); + } +} \ No newline at end of file diff --git a/src/Menaver.NetBitSet.Tests.Perf/Properties/launchSettings.json b/src/Menaver.NetBitSet.Tests.Perf/Properties/launchSettings.json index 6230cf6..5e04964 100644 --- a/src/Menaver.NetBitSet.Tests.Perf/Properties/launchSettings.json +++ b/src/Menaver.NetBitSet.Tests.Perf/Properties/launchSettings.json @@ -11,9 +11,13 @@ "commandName": "Project", "commandLineArgs": "NetBitSetBitwiseInvertPerfTestSuit" }, - "Menaver.NetBitSet.Tests.Perf: NetBitSetBitwiseShiftPerfTestSuit": { + "Menaver.NetBitSet.Tests.Perf: NetBitSetBitwiseShiftOverSmallDataPerfTestSuit": { "commandName": "Project", - "commandLineArgs": "NetBitSetBitwiseShiftPerfTestSuit" + "commandLineArgs": "NetBitSetBitwiseShiftOverSmallDataPerfTestSuit" + }, + "Menaver.NetBitSet.Tests.Perf: NetBitSetBitwiseShiftOverBigDataPerfTestSuit": { + "commandName": "Project", + "commandLineArgs": "NetBitSetBitwiseShiftOverBigDataPerfTestSuit" }, "Menaver.NetBitSet.Tests.Perf: NetBitSetConversionPerfTestSuit": { "commandName": "Project", diff --git a/src/Menaver.NetBitSet.Tests/NetBitSetMethodBitWiseTests.cs b/src/Menaver.NetBitSet.Tests/NetBitSetMethodBitWiseTests.cs index 37e32ab..c8ef42b 100644 --- a/src/Menaver.NetBitSet.Tests/NetBitSetMethodBitWiseTests.cs +++ b/src/Menaver.NetBitSet.Tests/NetBitSetMethodBitWiseTests.cs @@ -1195,4 +1195,204 @@ public void BitWise_ShiftLeft_Bit_Count_BinaryStringFits( // assert Assert.That(changedBinaryString == expectedBinaryString); } + + [TestCase(64, 1, Bit.False, 32)] + [TestCase(64, 2, Bit.False, 16)] + [TestCase(64, 3, Bit.False, 8)] + [TestCase(64, 4, Bit.False, 4)] + [TestCase(64, 1, Bit.True, 160)] + [TestCase(64, 2, Bit.True, 208)] + [TestCase(64, 3, Bit.True, 232)] + [TestCase(64, 4, Bit.True, 244)] + public void BitWise_ShiftRight_Byte_Count_ChangedValueFits( + byte value, + int count, + Bit shiftInBit, + byte expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftRight((ulong)count, shiftInBit); + var changedValue = netBitSet.ToByte(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((ushort)4096, 1, Bit.False, (ushort)2048)] + [TestCase((ushort)4096, 2, Bit.False, (ushort)1024)] + [TestCase((ushort)4096, 3, Bit.False, (ushort)512)] + [TestCase((ushort)4096, 4, Bit.False, (ushort)256)] + [TestCase((ushort)4096, 1, Bit.True, (ushort)34816)] + [TestCase((ushort)4096, 2, Bit.True, (ushort)50176)] + [TestCase((ushort)4096, 3, Bit.True, (ushort)57856)] + [TestCase((ushort)4096, 4, Bit.True, (ushort)61696)] + public void BitWise_ShiftRight_UShort_Count_ChangedValueFits( + ushort value, + int count, + Bit shiftInBit, + ushort expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftRight((ulong)count, shiftInBit); + var changedValue = netBitSet.ToUShort(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((uint)1073741824, 1, Bit.False, (uint)536870912)] + [TestCase((uint)1073741824, 2, Bit.False, (uint)268435456)] + [TestCase((uint)1073741824, 3, Bit.False, (uint)134217728)] + [TestCase((uint)1073741824, 4, Bit.False, (uint)67108864)] + [TestCase((uint)1073741824, 1, Bit.True, 2684354560)] + [TestCase((uint)1073741824, 2, Bit.True, 3489660928)] + [TestCase((uint)1073741824, 3, Bit.True, 3892314112)] + [TestCase((uint)1073741824, 4, Bit.True, 4093640704)] + public void BitWise_ShiftRight_UInt_Count_ChangedValueFits( + uint value, + int count, + Bit shiftInBit, + uint expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftRight((ulong)count, shiftInBit); + var changedValue = netBitSet.ToUInt(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((ulong)4611686018427387904, 1, Bit.False, (ulong)2305843009213693952)] + [TestCase((ulong)4611686018427387904, 2, Bit.False, (ulong)1152921504606846976)] + [TestCase((ulong)4611686018427387904, 3, Bit.False, (ulong)576460752303423488)] + [TestCase((ulong)4611686018427387904, 4, Bit.False, (ulong)288230376151711744)] + [TestCase((ulong)4611686018427387904, 1, Bit.True, 11529215046068469760)] + [TestCase((ulong)4611686018427387904, 2, Bit.True, 14987979559889010688)] + [TestCase((ulong)4611686018427387904, 3, Bit.True, 16717361816799281152)] + [TestCase((ulong)4611686018427387904, 4, Bit.True, 17582052945254416384)] + public void BitWise_ShiftRight_ULong_Count_ChangedValueFits( + ulong value, + int count, + Bit shiftInBit, + ulong expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftRight((ulong)count, shiftInBit); + var changedValue = netBitSet.ToULong(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase(8, 1, Bit.False, 16)] + [TestCase(8, 2, Bit.False, 32)] + [TestCase(8, 3, Bit.False, 64)] + [TestCase(8, 4, Bit.False, 128)] + [TestCase(8, 1, Bit.True, 17)] + [TestCase(8, 2, Bit.True, 35)] + [TestCase(8, 3, Bit.True, 71)] + [TestCase(8, 4, Bit.True, 143)] + public void BitWise_ShiftLeft_Byte_Count_ChangedValueFits( + byte value, + int count, + Bit shiftInBit, + byte expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftLeft((ulong)count, shiftInBit); + var changedValue = netBitSet.ToByte(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((ushort)4096, 1, Bit.False, (ushort)8192)] + [TestCase((ushort)4096, 2, Bit.False, (ushort)16384)] + [TestCase((ushort)4096, 3, Bit.False, (ushort)32768)] + [TestCase((ushort)4096, 4, Bit.False, (ushort)0)] + [TestCase((ushort)4096, 1, Bit.True, (ushort)8193)] + [TestCase((ushort)4096, 2, Bit.True, (ushort)16387)] + [TestCase((ushort)4096, 3, Bit.True, (ushort)32775)] + [TestCase((ushort)4096, 4, Bit.True, (ushort)15)] + public void BitWise_ShiftLeft_UShort_Count_ChangedValueFits( + ushort value, + int count, + Bit shiftInBit, + ushort expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftLeft((ulong)count, shiftInBit); + var changedValue = netBitSet.ToUShort(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((uint)4096, 1, Bit.False, (uint)8192)] + [TestCase((uint)4096, 2, Bit.False, (uint)16384)] + [TestCase((uint)4096, 3, Bit.False, (uint)32768)] + [TestCase((uint)4096, 4, Bit.False, (uint)65536)] + [TestCase((uint)4096, 1, Bit.True, (uint)8193)] + [TestCase((uint)4096, 2, Bit.True, (uint)16387)] + [TestCase((uint)4096, 3, Bit.True, (uint)32775)] + [TestCase((uint)4096, 4, Bit.True, (uint)65551)] + public void BitWise_ShiftLeft_UInt_Count_ChangedValueFits( + uint value, + int count, + Bit shiftInBit, + uint expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftLeft((ulong)count, shiftInBit); + var changedValue = netBitSet.ToUInt(); + + // assert + Assert.That(changedValue == expectedValue); + } + + [TestCase((ulong)1073741824, 1, Bit.False, (ulong)2147483648)] + [TestCase((ulong)1073741824, 2, Bit.False, (ulong)4294967296)] + [TestCase((ulong)1073741824, 3, Bit.False, (ulong)8589934592)] + [TestCase((ulong)1073741824, 4, Bit.False, (ulong)17179869184)] + [TestCase((ulong)1073741824, 1, Bit.True, (ulong)2147483649)] + [TestCase((ulong)1073741824, 2, Bit.True, (ulong)4294967299)] + [TestCase((ulong)1073741824, 3, Bit.True, (ulong)8589934599)] + [TestCase((ulong)1073741824, 4, Bit.True, (ulong)17179869199)] + public void BitWise_ShiftLeft_ULong_Count_ChangedValueFits( + ulong value, + int count, + Bit shiftInBit, + ulong expectedValue) + { + // arrange + var netBitSet = new NetBitSet(value); + + // act + netBitSet.ShiftLeft((ulong)count, shiftInBit); + var changedValue = netBitSet.ToULong(); + + // assert + Assert.That(changedValue == expectedValue); + } } \ No newline at end of file diff --git a/src/Menaver.NetBitSet.Tests/NetBitSetMethodConvertNegativeTests.cs b/src/Menaver.NetBitSet.Tests/NetBitSetMethodConvertNegativeTests.cs deleted file mode 100644 index 6b66f89..0000000 --- a/src/Menaver.NetBitSet.Tests/NetBitSetMethodConvertNegativeTests.cs +++ /dev/null @@ -1,207 +0,0 @@ -using NUnit.Framework.Internal; - -namespace Menaver.NetBitSet.Tests; - -[TestFixture] -public class NetBitSetMethodConvertNegativeTests -{ - private static readonly Randomizer Randomizer = Randomizer.CreateRandomizer(); - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.ThirtyTwo)] - [TestCase(WordLength.SixtyFour)] - public void SByte_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextSByte(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToSBytes(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.ThirtyTwo)] - [TestCase(WordLength.SixtyFour)] - public void Byte_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextByte(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToBytes(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.ThirtyTwo)] - [TestCase(WordLength.SixtyFour)] - public void Short_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextShort(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToShorts(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.ThirtyTwo)] - [TestCase(WordLength.SixtyFour)] - public void UShort_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextUShort(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToUShorts(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.SixtyFour)] - public void Int_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.Next(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToInts(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.SixtyFour)] - public void UInt_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextUInt(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToUInts(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.ThirtyTwo)] - public void Long_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextLong(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToLongs(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.ThirtyTwo)] - public void ULong_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextULong(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToULongs(); - } - - // assert - Assert.Throws(Action); - } - - [TestCase(WordLength.NotFixed)] - [TestCase(WordLength.One)] - [TestCase(WordLength.Eight)] - [TestCase(WordLength.Sixteen)] - [TestCase(WordLength.ThirtyTwo)] - public void Double_RandomValue_NotMarchingWordLength_ThrowsInvalidOperationException( - WordLength wordLength) - { - // arrange - var randomValue = Randomizer.NextDouble(); - var netBitSet = new NetBitSet(randomValue, wordLength); - - // act - void Action() - { - netBitSet.ToDoubles(); - } - - // assert - Assert.Throws(Action); - } -} \ No newline at end of file diff --git a/src/Menaver.NetBitSet/Internals/BitArrayConverter.cs b/src/Menaver.NetBitSet/Internals/BitArrayConverter.cs index 0b7aa62..8f91fdf 100644 --- a/src/Menaver.NetBitSet/Internals/BitArrayConverter.cs +++ b/src/Menaver.NetBitSet/Internals/BitArrayConverter.cs @@ -7,17 +7,6 @@ namespace Menaver.NetBitSet.Internals; internal static class BitArrayConverter { - public static void CheckByWordLength( - WordLength currentWordLength, - WordLength targetWordLength) - { - if (currentWordLength != targetWordLength) - { - throw new InvalidOperationException( - $"Word length does not match. Current: {currentWordLength}. Expected: {targetWordLength}."); - } - } - public static void CheckByElementCount( ulong elementCount, WordLength targetWordLength) diff --git a/src/Menaver.NetBitSet/Menaver.NetBitSet.csproj b/src/Menaver.NetBitSet/Menaver.NetBitSet.csproj index bdbc868..cd21402 100644 --- a/src/Menaver.NetBitSet/Menaver.NetBitSet.csproj +++ b/src/Menaver.NetBitSet/Menaver.NetBitSet.csproj @@ -7,15 +7,15 @@ enable $(MSBuildProjectName) - 1.0.3 - 1.0.3 + 1.1.0 + 1.1.0 https://github.com/Menaver/menaver.netbitset git Inspired by std::bitset from C++, NetBitSet represents a .NET implementation of a fixed-size sequence of bits. NetBitSet gives you an ability to operate with data on a bit level, it can be manipulated by standard logic operators, cloned, converted to and from basic CTS numeric data types, strings and even abstract objects. - Update description. + Improved shifting performance. true true diff --git a/src/Menaver.NetBitSet/NetBitSet.Methods.Bitwise.cs b/src/Menaver.NetBitSet/NetBitSet.Methods.Bitwise.cs index b1f0f9a..439da11 100644 --- a/src/Menaver.NetBitSet/NetBitSet.Methods.Bitwise.cs +++ b/src/Menaver.NetBitSet/NetBitSet.Methods.Bitwise.cs @@ -1,4 +1,5 @@ -using Menaver.NetBitSet.Extensions; +using System.Collections; +using Menaver.NetBitSet.Extensions; using Menaver.NetBitSet.Interfaces; using Menaver.NetBitSet.Internals; @@ -427,34 +428,102 @@ public void ShiftLeft(ulong count, double shiftInBit) public void ShiftLeft(ulong count, Bit shiftInBit) { var elementCount = Count; - var iterationCount = elementCount - 1; for (ulong i = 0; i < count; i++) { - if (elementCount <= int.MaxValue) + switch (elementCount) { - // a little optimization: if element count fits the 1-dimensional BitArray size limit, - // let's then do the shift over this array only, - // without needing to calculate a complex index on each iteration + case 8: + { + // convert to byte + var temp = new byte[1]; + _containers[0].CopyTo(temp, 0); + var register = temp[0]; + + register <<= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (byte)1 : (byte)0; - var shiftInBitBool = shiftInBit.ToBool(); - var iterationCountInt = (int)iterationCount; + register = (byte)(register | shiftInBitConverted); - for (var j = iterationCountInt; j > 0; j--) + _containers[0] = new BitArray(new byte[] { register }); + } + break; + case 16: { - _containers[0][j] = _containers[0][j - 1]; + // convert to ushort + var temp = new byte[2]; + _containers[0].CopyTo(temp, 0); + var register = BitConverter.ToUInt16(temp, 0); + + register <<= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (ushort)1 : (ushort)0; + + register = (ushort)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); } + break; + case 32: + { + // convert to uint + var temp = new uint[1]; + _containers[0].CopyTo(temp, 0); + var register = temp[0]; - _containers[0][0] = shiftInBitBool; - } - else - { - for (var j = iterationCount; j > 0; j--) + register <<= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (uint)1 : (uint)0; + + register = (uint)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); + } + break; + case 64: { - this[j] = this[j - 1]; + // convert to ulong + var temp = new byte[8]; + _containers[0].CopyTo(temp, 0); + var register = BitConverter.ToUInt64(temp, 0); + + register <<= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (ulong)1 : (ulong)0; + + register = (ulong)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); } + break; + case <= int.MaxValue: + { + // a little optimization: if element count fits the 1-dimensional BitArray size limit, + // let's then do the shift over this array only, + // without needing to calculate a complex index on each iteration - this[0] = shiftInBit; + var shiftInBitBool = shiftInBit.ToBool(); + var iterationCountInt = (int)elementCount - 1; + + for (var j = iterationCountInt; j > 0; j--) + { + _containers[0][j] = _containers[0][j - 1]; + } + + _containers[0][0] = shiftInBitBool; + } + break; + default: + { + for (var j = elementCount - 1; j > 0; j--) + { + this[j] = this[j - 1]; + } + + this[0] = shiftInBit; + } + break; } } } @@ -466,30 +535,103 @@ public void ShiftRight(ulong count, Bit shiftInBit) for (ulong i = 0; i < count; i++) { - if (elementCount <= int.MaxValue) + switch (elementCount) { - // a little optimization: if element count fits the 1-dimensional BitArray size limit, - // let's then do the shift over this array only, - // without needing to calculate a complex index on each iteration + case 8: + { + // convert to byte + var temp = new byte[1]; + _containers[0].CopyTo(temp, 0); + var register = temp[0]; + + register >>= 1; - var shiftInBitBool = shiftInBit.ToBool(); - var iterationCountInt = (int)iterationCount; + var shiftInBitConverted = shiftInBit == Bit.True ? (byte)1 : (byte)0; + shiftInBitConverted = (byte)(shiftInBitConverted << 7); - for (var j = 0; j < iterationCountInt; j++) + register = (byte)(register | shiftInBitConverted); + + _containers[0] = new BitArray(new byte[] { register }); + } + break; + case 16: { - _containers[0][j] = _containers[0][j + 1]; + // convert to ushort + var temp = new byte[2]; + _containers[0].CopyTo(temp, 0); + var register = BitConverter.ToUInt16(temp, 0); + + register >>= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (ushort)1 : (ushort)0; + shiftInBitConverted = (ushort)(shiftInBitConverted << 15); + + register = (ushort)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); } + break; + case 32: + { + // convert to uint + var temp = new uint[1]; + _containers[0].CopyTo(temp, 0); + var register = temp[0]; - _containers[0][iterationCountInt] = shiftInBitBool; - } - else - { - for (ulong j = 0; j < iterationCount; j++) + register >>= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (uint)1 : (uint)0; + shiftInBitConverted = (uint)(shiftInBitConverted << 31); + + register = (uint)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); + } + break; + case 64: { - this[j] = this[j + 1]; + // convert to ulong + var temp = new byte[8]; + _containers[0].CopyTo(temp, 0); + var register = BitConverter.ToUInt64(temp, 0); + + register >>= 1; + + var shiftInBitConverted = shiftInBit == Bit.True ? (ulong)1 : (ulong)0; + shiftInBitConverted = (ulong)(shiftInBitConverted << 63); + + register = (ulong)(register | shiftInBitConverted); + + _containers[0] = new BitArray(BitConverter.GetBytes(register)); } + break; + case <= int.MaxValue: + { + // a little optimization: if element count fits the 1-dimensional BitArray size limit, + // let's then do the shift over this array only, + // without needing to calculate a complex index on each iteration - this[iterationCount] = shiftInBit; + var shiftInBitBool = shiftInBit.ToBool(); + var iterationCountInt = (int)iterationCount; + + for (var j = 0; j < iterationCountInt; j++) + { + _containers[0][j] = _containers[0][j + 1]; + } + + _containers[0][iterationCountInt] = shiftInBitBool; + } + break; + default: + { + for (ulong j = 0; j < iterationCount; j++) + { + this[j] = this[j + 1]; + } + + this[iterationCount] = shiftInBit; + } + break; } } } diff --git a/src/Menaver.NetBitSet/NetBitSet.Methods.Converts.cs b/src/Menaver.NetBitSet/NetBitSet.Methods.Converts.cs index bbf9802..9db7ca6 100644 --- a/src/Menaver.NetBitSet/NetBitSet.Methods.Converts.cs +++ b/src/Menaver.NetBitSet/NetBitSet.Methods.Converts.cs @@ -110,7 +110,6 @@ public bool[] ToBools() /// The data converted. public sbyte[] ToSBytes() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Byte); BitArrayConverter.CheckByElementCount(Count, WordLengths.Byte); return BitArrayConverter.ConvertToSBytes(_containers); @@ -122,7 +121,6 @@ public sbyte[] ToSBytes() /// The data converted. public byte[] ToBytes() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Byte); BitArrayConverter.CheckByElementCount(Count, WordLengths.Byte); return BitArrayConverter.ConvertToBytes(_containers); @@ -134,7 +132,6 @@ public byte[] ToBytes() /// The data converted. public short[] ToShorts() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Short); BitArrayConverter.CheckByElementCount(Count, WordLengths.Short); return BitArrayConverter.ConvertToShorts(_containers); @@ -146,7 +143,6 @@ public short[] ToShorts() /// The data converted. public ushort[] ToUShorts() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Short); BitArrayConverter.CheckByElementCount(Count, WordLengths.Short); return BitArrayConverter.ConvertToUShorts(_containers); @@ -158,7 +154,6 @@ public ushort[] ToUShorts() /// The data converted. public int[] ToInts() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Int); BitArrayConverter.CheckByElementCount(Count, WordLengths.Int); return BitArrayConverter.ConvertToInts(_containers); @@ -170,7 +165,6 @@ public int[] ToInts() /// The data converted. public uint[] ToUInts() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Int); BitArrayConverter.CheckByElementCount(Count, WordLengths.Int); return BitArrayConverter.ConvertToUInts(_containers); @@ -182,7 +176,6 @@ public uint[] ToUInts() /// The data converted. public long[] ToLongs() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Long); BitArrayConverter.CheckByElementCount(Count, WordLengths.Long); return BitArrayConverter.ConvertToLongs(_containers); @@ -194,7 +187,6 @@ public long[] ToLongs() /// The data converted. public ulong[] ToULongs() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Long); BitArrayConverter.CheckByElementCount(Count, WordLengths.Long); return BitArrayConverter.ConvertToULongs(_containers); @@ -206,7 +198,6 @@ public ulong[] ToULongs() /// The data converted. public double[] ToDoubles() { - BitArrayConverter.CheckByWordLength(WordLength, WordLengths.Double); BitArrayConverter.CheckByElementCount(Count, WordLengths.Double); return BitArrayConverter.ConvertToDoubles(_containers);