You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
9.9 KiB
359 lines
9.9 KiB
#if FAT |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Threading; |
|
using LinqInternal.Collections.ThreadSafe; |
|
using LinqInternal.Core; |
|
using LinqInternal.Threading; |
|
|
|
namespace LinqInternal.Collections.Specialized |
|
{ |
|
[Serializable] |
|
internal sealed partial class FlagArray |
|
{ |
|
private readonly IReadOnlyCollection<bool> _asReadOnly; |
|
private readonly int _capacity; |
|
private int[] _entries; |
|
|
|
public FlagArray(FlagArray prototype) |
|
{ |
|
if (ReferenceEquals(prototype, null)) |
|
{ |
|
throw new ArgumentNullException("prototype", "prototype is null."); |
|
} |
|
_capacity = prototype._capacity; |
|
_entries = ArrayReservoir<int>.GetArray(GetLength(_capacity)); |
|
prototype._entries.CopyTo(_entries, 0); |
|
_asReadOnly = new ExtendedReadOnlyCollection<bool>(this); |
|
} |
|
|
|
public FlagArray(int capacity) |
|
{ |
|
if (capacity < 0) |
|
{ |
|
throw new ArgumentOutOfRangeException("capacity", "length < 0"); |
|
} |
|
_capacity = capacity; |
|
_entries = ArrayReservoir<int>.GetArray(GetLength(_capacity)); |
|
_asReadOnly = new ExtendedReadOnlyCollection<bool>(this); |
|
} |
|
|
|
public FlagArray(int capacity, bool defaultValue) |
|
: this(capacity) |
|
{ |
|
if (defaultValue) |
|
{ |
|
Fill(true); |
|
} |
|
} |
|
|
|
~FlagArray() |
|
{ |
|
// Assume anything could have been set to null, start no sync operation, this could be running during DomainUnload |
|
if (!GCMonitor.FinalizingForUnload) |
|
{ |
|
RecycleExtracted(); |
|
} |
|
} |
|
|
|
public int Capacity |
|
{ |
|
get { return _capacity; } |
|
} |
|
|
|
public int Count |
|
{ |
|
get |
|
{ |
|
var count = 0; |
|
var index = 0; |
|
var newindex = 0; |
|
foreach (var entry in _entries) |
|
{ |
|
newindex += 32; |
|
if (newindex <= _capacity) |
|
{ |
|
count += NumericHelper.PopulationCount(entry); |
|
index = newindex; |
|
} |
|
else |
|
{ |
|
foreach (var bit in entry.BinaryReverse().BitsBinary()) |
|
{ |
|
if (bit == 1) |
|
{ |
|
count++; |
|
} |
|
index++; |
|
if (index == _capacity) |
|
{ |
|
break; |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
return count; |
|
} |
|
} |
|
|
|
public IEnumerable<int> Flags |
|
{ |
|
get |
|
{ |
|
var index = 0; |
|
foreach (var entry in _entries) |
|
{ |
|
if (entry == 0) |
|
{ |
|
index += 32; |
|
if (index >= _capacity) |
|
{ |
|
yield break; |
|
} |
|
} |
|
else |
|
{ |
|
foreach (var bit in entry.BinaryReverse().BitsBinary()) |
|
{ |
|
if (bit == 1) |
|
{ |
|
yield return index; |
|
} |
|
index++; |
|
if (index == _capacity) |
|
{ |
|
yield break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
bool ICollection<bool>.IsReadOnly |
|
{ |
|
get { return false; } |
|
} |
|
|
|
public bool this[int index] |
|
{ |
|
get |
|
{ |
|
var entryIndex = index >> 5; |
|
var bit = index & 31; |
|
var mask = 1 << bit; |
|
return GetBit(entryIndex, mask); |
|
} |
|
set |
|
{ |
|
var entryIndex = index >> 5; |
|
var bit = index & 31; |
|
var mask = 1 << bit; |
|
if (value) |
|
{ |
|
SetBit(entryIndex, mask); |
|
} |
|
else |
|
{ |
|
UnsetBit(entryIndex, mask); |
|
} |
|
} |
|
} |
|
|
|
public FlagArray Clone() |
|
{ |
|
return new FlagArray(this); |
|
} |
|
|
|
public bool Contains(bool item) |
|
{ |
|
var index = 0; |
|
var newindex = 0; |
|
var check = item ? 0 : -1; |
|
foreach (var entry in _entries) |
|
{ |
|
newindex += 32; |
|
if (newindex <= _capacity) |
|
{ |
|
if (entry != check) |
|
{ |
|
return true; |
|
} |
|
index = newindex; |
|
} |
|
else |
|
{ |
|
foreach (var bit in entry.BinaryReverse().BitsBinary()) |
|
{ |
|
if ((bit == 1) == item) |
|
{ |
|
return true; |
|
} |
|
index++; |
|
if (index == _capacity) |
|
{ |
|
break; |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
public bool Contains(bool item, IEqualityComparer<bool> comparer) |
|
{ |
|
return System.Linq.Enumerable.Contains(this, item, comparer); |
|
} |
|
|
|
public void CopyTo(bool[] array, int arrayIndex) |
|
{ |
|
Extensions.CanCopyTo(_capacity, array, arrayIndex); |
|
Extensions.CopyTo(this, array, arrayIndex); |
|
} |
|
|
|
public void CopyTo(bool[] array) |
|
{ |
|
Extensions.CanCopyTo(_capacity, array); |
|
Extensions.CopyTo(this, array); |
|
} |
|
|
|
public void CopyTo(bool[] array, int arrayIndex, int countLimit) |
|
{ |
|
Extensions.CanCopyTo(array, arrayIndex, countLimit); |
|
Extensions.CopyTo(this, array, arrayIndex, countLimit); |
|
} |
|
|
|
public IEnumerator<bool> GetEnumerator() |
|
{ |
|
var index = 0; |
|
foreach (var entry in _entries) |
|
{ |
|
foreach (var bit in entry.BinaryReverse().BitsBinary()) |
|
{ |
|
yield return bit == 1; |
|
index++; |
|
if (index == _capacity) |
|
{ |
|
yield break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
#if !NETCOREAPP1_1 |
|
object ICloneable.Clone() |
|
{ |
|
return Clone(); |
|
} |
|
#endif |
|
|
|
void ICollection<bool>.Add(bool item) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
|
|
void ICollection<bool>.Clear() |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
|
|
bool ICollection<bool>.Remove(bool item) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
|
|
void IList<bool>.Insert(int index, bool item) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
|
|
void IList<bool>.RemoveAt(int index) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
|
|
public int IndexOf(bool item) |
|
{ |
|
return Extensions.IndexOf(this, item); |
|
} |
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
{ |
|
return GetEnumerator(); |
|
} |
|
|
|
private void Fill(bool value) |
|
{ |
|
var entryValue = value ? unchecked((int)0xffffffff) : 0; |
|
for (var index = 0; index < GetLength(_capacity); index++) |
|
{ |
|
_entries[index] = entryValue; |
|
} |
|
} |
|
|
|
private bool GetBit(int index, int mask) |
|
{ |
|
return (Volatile.Read(ref _entries[index]) & mask) != 0; |
|
} |
|
|
|
private int GetLength(int length) |
|
{ |
|
return (length >> 5) + ((length & 31) == 0 ? 0 : 1); |
|
} |
|
|
|
private void RecycleExtracted() |
|
{ |
|
// Assume anything could have been set to null, start no sync operation, this could be running during DomainUnload |
|
var entries = _entries; |
|
if (entries != null) |
|
{ |
|
ArrayReservoir<int>.DonateArray(entries); |
|
_entries = null; |
|
} |
|
} |
|
|
|
private void SetBit(int index, int mask) |
|
{ |
|
again: |
|
var readed = Volatile.Read(ref _entries[index]); |
|
if ((readed & mask) == 0) |
|
{ |
|
if (Interlocked.CompareExchange(ref _entries[index], readed | mask, readed) != readed) |
|
{ |
|
goto again; |
|
} |
|
} |
|
} |
|
|
|
private void UnsetBit(int index, int mask) |
|
{ |
|
again: |
|
var readed = Volatile.Read(ref _entries[index]); |
|
if ((readed & mask) != 0) |
|
{ |
|
if (Interlocked.CompareExchange(ref _entries[index], readed & ~mask, readed) != readed) |
|
{ |
|
goto again; |
|
} |
|
} |
|
} |
|
} |
|
|
|
internal sealed partial class FlagArray : IList<bool>, IExtendedCollection<bool>, ICloneable<FlagArray> |
|
{ |
|
IReadOnlyCollection<bool> IExtendedCollection<bool>.AsReadOnly |
|
{ |
|
get { return _asReadOnly; } |
|
} |
|
|
|
bool IExtendedCollection<bool>.Remove(bool item, IEqualityComparer<bool> comparer) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
} |
|
} |
|
|
|
#endif |