Skip to content

Instantly share code, notes, and snippets.

@copygirl
Created October 10, 2015 04:32
Show Gist options
  • Save copygirl/89a20e0cab55cebe1220 to your computer and use it in GitHub Desktop.
Save copygirl/89a20e0cab55cebe1220 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OtherEngine.Utility
{
/// <summary> Helper class that stores a fixed number of bits, provides
/// indexed access and implements bitwise and equality operators. </summary>
public class BitArray : IEquatable<BitArray>, IEnumerable<bool>
{
const int INT_SHIFT = 5;
const int BIT_AND = 31;
readonly int[] _ints;
#region Public properties
/// <summary> Gets the length of this BitArray. </summary>
public int Length { get; private set; }
/// <summary> Gets or sets an individual bit in this BitArray. </summary>
public bool this[int index] {
get {
if ((index < 0) || (index >= Length))
throw new ArgumentOutOfRangeException();
return ((_ints[index >> INT_SHIFT] & (1 << (index & BIT_AND))) != 0);
}
set {
if ((index < 0) || (index >= Length))
throw new ArgumentOutOfRangeException();
if (value) _ints[index >> INT_SHIFT] |= (1 << (index & BIT_AND));
else _ints[index >> INT_SHIFT] &= ~(1 << (index & BIT_AND));
}
}
#endregion
#region Constructors
public BitArray(int length)
{
if (length <= 0)
throw new ArgumentOutOfRangeException("length", "Length must be positive");
_ints = new int[GetArraySize(length)];
Length = length;
}
public BitArray(int[] ints, int bits)
{
if (ints == null)
throw new ArgumentNullException("ints");
if (bits <= 0)
throw new ArgumentOutOfRangeException("bits", "Bit count must be positive");
if (ints.Length != GetArraySize(bits))
throw new ArgumentException(string.Format(
"ints array size ({0}) incorrect to hold this number of bits ({1}), should be {2}",
ints.Length, bits, GetArraySize(bits)), "ints");
_ints = ints;
Length = bits;
}
public BitArray(BitArray bits)
{
if (bits == null)
throw new ArgumentNullException("bits");
_ints = bits._ints.ArrayCopy();
Length = bits.Length;
}
#endregion
#region Public methods
/// <summary> Returns if any of the bits in this BitArray are set. </summary>
public bool Any()
{
return _ints.Any(i => (i != 0));
}
/// <summary> Returns the underlying int[] that's used to store the bits. </summary>
public int[] GetUnderlyingArray()
{
return _ints;
}
#endregion
#region Static methods
/// <summary> Returns the size an int[] has to be to hold this many bits. </summary>
public static int GetArraySize(int bits)
{
return (bits + BIT_AND) >> INT_SHIFT;
}
#endregion
#region Bitwise operators
public static BitArray operator ~(BitArray bits)
{
var result = new BitArray(bits.Length);
for (var i = 0; i < result._ints.Length; i++)
result._ints[i] = ~bits._ints[i];
result._ints[result._ints.Length - 1] &= ~(~0 << (result.Length & BIT_AND));
return result;
}
public static BitArray operator &(BitArray left, BitArray right)
{
var length = Math.Min(left.Length, right.Length);
var tesult = new BitArray(length);
for (var i = 0; i < tesult._ints.Length; i++)
tesult._ints[i] = left._ints[i] & right._ints[i];
return tesult;
}
public static BitArray operator |(BitArray left, BitArray right)
{
var length = Math.Max(left.Length, right.Length);
var result = new BitArray(length);
for (var i = 0; i < result._ints.Length; i++)
result._ints[i] = left.GetIntOrDefault(i) | right.GetIntOrDefault(i);
return result;
}
public static BitArray operator ^(BitArray left, BitArray right)
{
var length = Math.Max(left.Length, right.Length);
var result = new BitArray(length);
for (var i = 0; i < result._ints.Length; i++)
result._ints[i] = left.GetIntOrDefault(i) ^ right.GetIntOrDefault(i);
return result;
}
int GetIntOrDefault(int index, int @default = 0)
{
return ((index < _ints.Length) ? _ints[index] : @default);
}
#endregion
#region Equality operators
public static bool operator ==(BitArray left, BitArray right)
{
var length = Math.Max(left._ints.Length, right._ints.Length);
for (var i = 0; i < length; i++)
if (left.GetIntOrDefault(i) != right.GetIntOrDefault(i))
return false;
return true;
}
public static bool operator !=(BitArray left, BitArray right)
{
return !(left == right);
}
#endregion
#region ToString, Equals and GetHashCode
public override string ToString()
{
var sb = new StringBuilder("[BitArray ");
foreach (var bit in this)
sb.Append(bit ? '1' : '0');
return sb.Append("]").ToString();
}
public override bool Equals(object obj)
{
return Equals(obj as BitArray);
}
public override int GetHashCode()
{
return HashHelper.ComputeHashCode(_ints.Precede(Length));
}
#endregion
#region IEquatable<BitArray> implementation
public bool Equals(BitArray other)
{
return ((other != null) && (other.Length == Length) && other._ints.SequenceEqual(_ints));
}
#endregion
#region IEnumerable<bool> implementation
public IEnumerator<bool> GetEnumerator()
{
return Enumerable.Range(0, Length).Select(i => this[i]).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment