Created
October 10, 2015 04:32
-
-
Save copygirl/89a20e0cab55cebe1220 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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