Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Diagnostics;
using System.Linq;
using System.Numerics;
using Xunit;

namespace System.Collections.Generic.Tests
Expand Down Expand Up @@ -205,29 +206,7 @@ private static int CalculateExpectedCapacity(int count)

// Then allocate arrays of size 4, 8, 16, etc.
count = Math.Max(count, 4);
return NextPowerOfTwo(count);
}

private static int NextPowerOfTwo(int value)
{
// Taken from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2

Debug.Assert(value >= 0);

// If the number is already a power of 2, we want to round to itself.
value--;

// Propogate 1-bits right: if the highest bit set is @ position n,
// then all of the bits to the right of position n will become set.
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;

// This yields a number of the form 2^N - 1.
// Add 1 to get a power of 2 with the bit set @ position n + 1.
return value + 1;
return (int)BitOperations.RoundUpToPowerOf2((uint)count);
}
}

Expand Down
15 changes: 2 additions & 13 deletions src/libraries/System.Buffers/tests/ArrayPool/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
Expand Down Expand Up @@ -278,23 +279,11 @@ public static void CanRentManySizedBuffers(ArrayPool<byte> pool)
for (int i = 1; i < 10000; i++)
{
byte[] buffer = pool.Rent(i);
Assert.Equal(i <= 16 ? 16 : RoundUpToPowerOf2(i), buffer.Length);
Assert.Equal(i <= 16 ? 16 : (int)BitOperations.RoundUpToPowerOf2((uint)i), buffer.Length);
pool.Return(buffer);
}
}

private static int RoundUpToPowerOf2(int i)
{
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
--i;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
return i + 1;
}

[Theory]
[InlineData(1, 16)]
[InlineData(15, 16)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,55 @@ public static class BitOperations
[CLSCompliant(false)]
public static bool IsPow2(ulong value) => (value & (value - 1)) == 0 && value != 0;

/// <summary>Round the given integral value up to a power of 2.</summary>
/// <summary>
/// Round the given integral value up to a power of 2.
/// </summary>
/// <param name="value">The value.</param>
internal static uint RoundUpToPowerOf2(uint value)
/// <returns>
/// The smallest power of 2 which is greater than or equal to <paramref name="value"/>.
/// If <paramref name="value"/> is 0 or the result overflows, returns 0.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static uint RoundUpToPowerOf2(uint value)
{
// TODO: https://github.com/dotnet/runtime/issues/43135
// When this is exposed publicly, decide on the behavior for the boundary cases...
// the accelerated and fallback paths differ.
Debug.Assert(value > 0 && value <= (uint.MaxValue / 2) + 1);

if (Lzcnt.IsSupported || ArmBase.IsSupported || X86Base.IsSupported)
{
return 1u << (32 - LeadingZeroCount(value - 1));
#if TARGET_64BIT
return (uint)(0x1_0000_0000ul >> LeadingZeroCount(value - 1));
#else
int shift = 32 - LeadingZeroCount(value - 1);
return (1u ^ (uint)(shift >> 5)) << shift;
#endif
}

// Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
--value;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
}


/// <summary>
/// Round the given integral value up to a power of 2.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>
/// The smallest power of 2 which is greater than or equal to <paramref name="value"/>.
/// If <paramref name="value"/> is 0 or the result overflows, returns 0.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static ulong RoundUpToPowerOf2(ulong value)
{
if (Lzcnt.X64.IsSupported || ArmBase.Arm64.IsSupported)
{
int shift = 64 - LeadingZeroCount(value - 1);
return (1ul ^ (ulong)(shift >> 6)) << shift;
}

// Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
Expand All @@ -92,6 +129,7 @@ internal static uint RoundUpToPowerOf2(uint value)
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return value + 1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,5 +388,53 @@ public static void BitOps_RotateRight_ulong()
Assert.Equal(value, BitOperations.RotateRight(value, int.MinValue)); // % 64 = 0
Assert.Equal(BitOperations.RotateLeft(value, 63), BitOperations.RotateRight(value, int.MaxValue)); // % 64 = 63
}

[Theory]
[InlineData(0u, 0u)]
[InlineData(1u, 1u)]
[InlineData(2u, 2u)]
[InlineData(0x0096u, 0x0100u)]
[InlineData(0x05CDu, 0x0800u)]
[InlineData(0x0932u, 0x1000u)]
[InlineData(0x0004_C911u, 0x0008_0000u)]
[InlineData(0x00E0_A2E2u, 0x0100_0000u)]
[InlineData(0x0988_0713u, 0x1000_0000u)]
[InlineData(0x30A4_9649u, 0x4000_0000u)]
[InlineData(0x7FFF_FFFFu, 0x8000_0000u)]
[InlineData(0x8000_0000u, 0x8000_0000u)]
[InlineData(0x8000_0001u, 0ul)]
[InlineData(0xFFFF_FFFFu, 0ul)]
public static void BitOps_RoundUpToPow2_uint(uint value, uint expected)
{
Assert.Equal(expected, BitOperations.RoundUpToPowerOf2(value));
}

[Theory]
[InlineData(0ul, 0ul)]
[InlineData(1ul, 1ul)]
[InlineData(2ul, 2ul)]
[InlineData(0x0096ul, 0x0100ul)]
[InlineData(0x05cdul, 0x0800ul)]
[InlineData(0x0932ul, 0x1000ul)]
[InlineData(0x0004_c911ul, 0x0008_0000ul)]
[InlineData(0x00e0_a2b2ul, 0x0100_0000ul)]
[InlineData(0x0988_0713ul, 0x1000_0000ul)]
[InlineData(0x30a4_9649ul, 0x4000_0000ul)]
[InlineData(0x7FFF_FFFFul, 0x8000_0000ul)]
[InlineData(0x8000_0000ul, 0x8000_0000ul)]
[InlineData(0x8000_0001ul, 0x1_0000_0000ul)]
[InlineData(0xFFFF_FFFFul, 0x1_0000_0000ul)]
[InlineData(0x0000_0003_343B_0D81ul, 0x0000_0004_0000_0000ul)]
[InlineData(0x0000_0D87_5EE2_8F19ul, 0x0000_1000_0000_0000ul)]
[InlineData(0x0006_2A08_4A7A_3A2Dul, 0x0008_0000_0000_0000ul)]
[InlineData(0x0101_BF76_4398_F791ul, 0x0200_0000_0000_0000ul)]
[InlineData(0x7FFF_FFFF_FFFF_FFFFul, 0x8000_0000_0000_0000ul)]
[InlineData(0x8000_0000_0000_0000ul, 0x8000_0000_0000_0000ul)]
[InlineData(0x8000_0000_0000_0001ul, 0ul)]
[InlineData(0xFFFF_FFFF_FFFF_FFFFul, 0ul)]
public static void BitOps_RoundUpToPow2_ulong(ulong value, ulong expected)
{
Assert.Equal(expected, BitOperations.RoundUpToPowerOf2(value));
}
}
}
4 changes: 4 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8196,6 +8196,10 @@ public static partial class BitOperations
public static uint RotateRight(uint value, int offset) { throw null; }
[System.CLSCompliantAttribute(false)]
public static ulong RotateRight(ulong value, int offset) { throw null; }
[System.CLSCompliantAttribute(false)]
public static uint RoundUpToPowerOf2(uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static ulong RoundUpToPowerOf2(ulong value) { throw null; }
public static int TrailingZeroCount(int value) { throw null; }
public static int TrailingZeroCount(long value) { throw null; }
[System.CLSCompliantAttribute(false)]
Expand Down