|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
namespace System.Collections.Specialized
{
/// <devdoc>
/// <para>Provides a simple light bit vector with easy integer or Boolean access to
/// a 32 bit storage.</para>
/// </devdoc>
public struct BitVector32 : IEquatable<BitVector32>
{
private uint _data;
/// <devdoc>
/// <para>Initializes a new instance of the BitVector32 structure with the specified internal data.</para>
/// </devdoc>
public BitVector32(int data)
{
_data = unchecked((uint)data);
}
/// <devdoc>
/// <para>Initializes a new instance of the BitVector32 structure with the information in the specified
/// value.</para>
/// </devdoc>
public BitVector32(BitVector32 value)
{
_data = value._data;
}
/// <devdoc>
/// <para>Gets or sets a value indicating whether all the specified bits are set.</para>
/// </devdoc>
public bool this[int bit]
{
get
{
return (_data & bit) == unchecked((uint)bit);
}
set
{
unchecked
{
if (value)
{
_data |= (uint)bit;
}
else
{
_data &= ~(uint)bit;
}
}
}
}
/// <devdoc>
/// <para>Gets or sets the value for the specified section.</para>
/// </devdoc>
public int this[Section section]
{
get
{
unchecked
{
return (int)((_data & (uint)(section.Mask << section.Offset)) >> section.Offset);
}
}
set
{
// The code should really have originally validated "(value & section.Mask) == value" with
// an exception (it instead validated it with a Debug.Assert, which does little good in a
// public method when in a Release build). We don't include such a check now as it would
// likely break things and for little benefit.
value <<= section.Offset;
int offsetMask = (0xFFFF & (int)section.Mask) << section.Offset;
_data = unchecked((_data & ~(uint)offsetMask) | ((uint)value & (uint)offsetMask));
}
}
/// <devdoc>
/// returns the raw data stored in this bit vector...
/// </devdoc>
public int Data
{
get
{
return unchecked((int)_data);
}
}
/// <devdoc>
/// <para> Creates the first mask in a series.</para>
/// </devdoc>
public static int CreateMask()
{
return CreateMask(0);
}
/// <devdoc>
/// Creates the next mask in a series.
/// </devdoc>
public static int CreateMask(int previous)
{
if (previous == 0)
{
return 1;
}
if (previous == unchecked((int)0x80000000))
{
throw new InvalidOperationException(SR.BitVectorFull);
}
return previous << 1;
}
/// <devdoc>
/// <para>Creates the first section in a series, with the specified maximum value.</para>
/// </devdoc>
public static Section CreateSection(short maxValue)
{
return CreateSectionHelper(maxValue, 0, 0);
}
/// <devdoc>
/// <para>Creates the next section in a series, with the specified maximum value.</para>
/// </devdoc>
public static Section CreateSection(short maxValue, Section previous)
{
return CreateSectionHelper(maxValue, previous.Mask, previous.Offset);
}
private static Section CreateSectionHelper(short maxValue, short priorMask, short priorOffset)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(maxValue);
short offset = (short)(priorOffset + BitOperations.PopCount((uint)(ushort)priorMask));
if (offset >= 32)
{
throw new InvalidOperationException(SR.BitVectorFull);
}
short mask = (short)(BitOperations.RoundUpToPowerOf2((uint)(ushort)maxValue + 1) - 1);
return new Section(mask, offset);
}
public override bool Equals([NotNullWhen(true)] object? o) => o is BitVector32 other && Equals(other);
/// <summary>Indicates whether the current instance is equal to another instance of the same type.</summary>
/// <param name="other">An instance to compare with this instance.</param>
/// <returns>true if the current instance is equal to the other instance; otherwise, false.</returns>
public bool Equals(BitVector32 other) => _data == other._data;
public override int GetHashCode() => _data.GetHashCode();
public static string ToString(BitVector32 value)
{
return string.Create(/*"BitVector32{".Length*/12 + /*32 bits*/32 + /*"}".Length"*/1, value, (dst, v) =>
{
ReadOnlySpan<char> prefix = "BitVector32{";
prefix.CopyTo(dst);
dst[dst.Length - 1] = '}';
int locdata = unchecked((int)v._data);
dst = dst.Slice(prefix.Length, 32);
for (int i = 0; i < dst.Length; i++)
{
dst[i] = (locdata & 0x80000000) != 0 ? '1' : '0';
locdata <<= 1;
}
});
}
public override string ToString()
{
return ToString(this);
}
/// <devdoc>
/// <para>
/// Represents an section of the vector that can contain a integer number.</para>
/// </devdoc>
public readonly struct Section : IEquatable<Section>
{
private readonly short _mask;
private readonly short _offset;
internal Section(short mask, short offset)
{
_mask = mask;
_offset = offset;
}
public short Mask => _mask;
public short Offset => _offset;
public override bool Equals([NotNullWhen(true)] object? o) => o is Section other && Equals(other);
public bool Equals(Section obj)
{
return obj._mask == _mask && obj._offset == _offset;
}
public static bool operator ==(Section a, Section b)
{
return a.Equals(b);
}
public static bool operator !=(Section a, Section b)
{
return !(a == b);
}
public override int GetHashCode() => HashCode.Combine(_mask, _offset);
public static string ToString(Section value)
{
return $"Section{{0x{value.Mask:x}, 0x{value.Offset:x}}}";
}
public override string ToString()
{
return ToString(this);
}
}
}
}
|