diff options
Diffstat (limited to 'ARMeilleure/Common')
| -rw-r--r-- | ARMeilleure/Common/BitMap.cs | 87 | ||||
| -rw-r--r-- | ARMeilleure/Common/BitMapPool.cs | 19 | ||||
| -rw-r--r-- | ARMeilleure/Common/BitUtils.cs | 42 | ||||
| -rw-r--r-- | ARMeilleure/Common/SortedIntegerList.cs | 73 | ||||
| -rw-r--r-- | ARMeilleure/Common/ThreadStaticPool.cs | 104 |
5 files changed, 266 insertions, 59 deletions
diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs index 9dff271b..35100536 100644 --- a/ARMeilleure/Common/BitMap.cs +++ b/ARMeilleure/Common/BitMap.cs @@ -1,20 +1,50 @@ using System.Collections; using System.Collections.Generic; +using System.Numerics; namespace ARMeilleure.Common { - class BitMap : IEnumerable<int> + class BitMap : IEnumerator<int> { - private const int IntSize = 32; + private const int IntSize = 64; private const int IntMask = IntSize - 1; - private List<int> _masks; + private List<long> _masks; + + private int _enumIndex; + private long _enumMask; + private int _enumBit; + + public int Current => _enumIndex * IntSize + _enumBit; + object IEnumerator.Current => Current; + + public BitMap() + { + _masks = new List<long>(0); + } public BitMap(int initialCapacity) { int count = (initialCapacity + IntMask) / IntSize; - _masks = new List<int>(count); + _masks = new List<long>(count); + + while (count-- > 0) + { + _masks.Add(0); + } + } + + public void Reset(int initialCapacity) + { + int count = (initialCapacity + IntMask) / IntSize; + + if (count > _masks.Capacity) + { + _masks.Capacity = count; + } + + _masks.Clear(); while (count-- > 0) { @@ -29,7 +59,7 @@ namespace ARMeilleure.Common int wordIndex = bit / IntSize; int wordBit = bit & IntMask; - int wordMask = 1 << wordBit; + long wordMask = 1L << wordBit; if ((_masks[wordIndex] & wordMask) != 0) { @@ -48,7 +78,7 @@ namespace ARMeilleure.Common int wordIndex = bit / IntSize; int wordBit = bit & IntMask; - int wordMask = 1 << wordBit; + long wordMask = 1L << wordBit; _masks[wordIndex] &= ~wordMask; } @@ -60,7 +90,7 @@ namespace ARMeilleure.Common int wordIndex = bit / IntSize; int wordBit = bit & IntMask; - return (_masks[wordIndex] & (1 << wordBit)) != 0; + return (_masks[wordIndex] & (1L << wordBit)) != 0; } public bool Set(BitMap map) @@ -71,7 +101,7 @@ namespace ARMeilleure.Common for (int index = 0; index < _masks.Count; index++) { - int newValue = _masks[index] | map._masks[index]; + long newValue = _masks[index] | map._masks[index]; if (_masks[index] != newValue) { @@ -92,7 +122,7 @@ namespace ARMeilleure.Common for (int index = 0; index < _masks.Count; index++) { - int newValue = _masks[index] & ~map._masks[index]; + long newValue = _masks[index] & ~map._masks[index]; if (_masks[index] != newValue) { @@ -105,6 +135,10 @@ namespace ARMeilleure.Common return modified; } + #region IEnumerable<long> Methods + + // Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating. + private void EnsureCapacity(int size) { while (_masks.Count * IntSize < size) @@ -115,24 +149,37 @@ namespace ARMeilleure.Common public IEnumerator<int> GetEnumerator() { - for (int index = 0; index < _masks.Count; index++) - { - int mask = _masks[index]; + Reset(); + return this; + } - while (mask != 0) + public bool MoveNext() + { + if (_enumMask != 0) + { + _enumMask &= ~(1L << _enumBit); + } + while (_enumMask == 0) + { + if (++_enumIndex >= _masks.Count) { - int bit = BitUtils.LowestBitSet(mask); - - mask &= ~(1 << bit); - - yield return index * IntSize + bit; + return false; } + _enumMask = _masks[_enumIndex]; } + _enumBit = BitOperations.TrailingZeroCount(_enumMask); + return true; } - IEnumerator IEnumerable.GetEnumerator() + public void Reset() { - return GetEnumerator(); + _enumIndex = -1; + _enumMask = 0; + _enumBit = 0; } + + public void Dispose() { } + +#endregion } }
\ No newline at end of file diff --git a/ARMeilleure/Common/BitMapPool.cs b/ARMeilleure/Common/BitMapPool.cs new file mode 100644 index 00000000..caba2317 --- /dev/null +++ b/ARMeilleure/Common/BitMapPool.cs @@ -0,0 +1,19 @@ +using System; + +namespace ARMeilleure.Common +{ + static class BitMapPool + { + public static BitMap Allocate(int initialCapacity) + { + BitMap result = ThreadStaticPool<BitMap>.Instance.Allocate(); + result.Reset(initialCapacity); + return result; + } + + public static void Release() + { + ThreadStaticPool<BitMap>.Instance.Clear(); + } + } +} diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs index 7a29dcff..00fc6e5b 100644 --- a/ARMeilleure/Common/BitUtils.cs +++ b/ARMeilleure/Common/BitUtils.cs @@ -1,24 +1,13 @@ +using System.Numerics; + namespace ARMeilleure.Common { static class BitUtils { - private const int DeBrujinSequence = 0x77cb531; - - private static readonly int[] DeBrujinLbsLut; - private static readonly sbyte[] HbsNibbleLut; static BitUtils() { - DeBrujinLbsLut = new int[32]; - - for (int index = 0; index < DeBrujinLbsLut.Length; index++) - { - uint lutIndex = (uint)(DeBrujinSequence * (1 << index)) >> 27; - - DeBrujinLbsLut[lutIndex] = index; - } - HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; } @@ -43,20 +32,7 @@ namespace ARMeilleure.Common public static int HighestBitSet(int value) { - if (value == 0) - { - return -1; - } - - for (int bit = 31; bit >= 0; bit--) - { - if (((value >> bit) & 1) != 0) - { - return bit; - } - } - - return -1; + return 31 - BitOperations.LeadingZeroCount((uint)value); } public static int HighestBitSetNibble(int value) @@ -64,18 +40,6 @@ namespace ARMeilleure.Common return HbsNibbleLut[value]; } - public static int LowestBitSet(int value) - { - if (value == 0) - { - return -1; - } - - int lsb = value & -value; - - return DeBrujinLbsLut[(uint)(DeBrujinSequence * lsb) >> 27]; - } - public static long Replicate(long bits, int size) { long output = 0; diff --git a/ARMeilleure/Common/SortedIntegerList.cs b/ARMeilleure/Common/SortedIntegerList.cs new file mode 100644 index 00000000..cceab62b --- /dev/null +++ b/ARMeilleure/Common/SortedIntegerList.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +namespace ARMeilleure.Common +{ + public class SortedIntegerList + { + private List<int> _items; + + public int Count => _items.Count; + + public int this[int index] + { + get + { + return _items[index]; + } + set + { + _items[index] = value; + } + } + + public SortedIntegerList() + { + _items = new List<int>(); + } + + public bool Add(int value) + { + if (_items.Count == 0 || value > Last()) + { + _items.Add(value); + return true; + } + else + { + int index = _items.BinarySearch(value); + if (index >= 0) + { + return false; + } + + _items.Insert(-1 - index, value); + return true; + } + } + + public int FindLessEqualIndex(int value) + { + int index = _items.BinarySearch(value); + return (index < 0) ? (-2 - index) : index; + } + + public void RemoveRange(int index, int count) + { + if (count > 0) + { + _items.RemoveRange(index, count); + } + } + + public int Last() + { + return _items[Count - 1]; + } + + public List<int> GetList() + { + return _items; + } + } +} diff --git a/ARMeilleure/Common/ThreadStaticPool.cs b/ARMeilleure/Common/ThreadStaticPool.cs new file mode 100644 index 00000000..cf3a7bb4 --- /dev/null +++ b/ARMeilleure/Common/ThreadStaticPool.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace ARMeilleure.Common +{ + internal class ThreadStaticPool<T> where T : class, new() + { + private const int PoolSizeIncrement = 200; + + [ThreadStatic] + private static ThreadStaticPool<T> _instance; + public static ThreadStaticPool<T> Instance + { + get + { + if (_instance == null) + { + PreparePool(0); // So that we can still use a pool when blindly initializing one. + } + return _instance; + } + } + + private static ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>>(); + + private static Stack<ThreadStaticPool<T>> GetPools(int groupId) + { + return _pools.GetOrAdd(groupId, x => new Stack<ThreadStaticPool<T>>()); + } + + public static void PreparePool(int groupId) + { + // Prepare the pool for this thread, ideally using an existing one from the specified group. + if (_instance == null) + { + Stack<ThreadStaticPool<T>> pools = GetPools(groupId); + lock (pools) + { + _instance = (pools.Count != 0) ? pools.Pop() : new ThreadStaticPool<T>(PoolSizeIncrement * 2); + } + } + } + + public static void ReturnPool(int groupId) + { + // Reset and return the pool for this thread to the specified group. + Stack<ThreadStaticPool<T>> pools = GetPools(groupId); + lock (pools) + { + _instance.Clear(); + pools.Push(_instance); + _instance = null; + } + } + + private T[] _pool; + private int _poolUsed = -1; + private int _poolSize; + + public ThreadStaticPool(int initialSize) + { + _pool = new T[initialSize]; + + for (int i = 0; i < initialSize; i++) + { + _pool[i] = new T(); + } + + _poolSize = initialSize; + } + + public T Allocate() + { + int index = Interlocked.Increment(ref _poolUsed); + if (index >= _poolSize) + { + IncreaseSize(); + } + return _pool[index]; + } + + private void IncreaseSize() + { + _poolSize += PoolSizeIncrement; + + T[] newArray = new T[_poolSize]; + Array.Copy(_pool, 0, newArray, 0, _pool.Length); + + for (int i = _pool.Length; i < _poolSize; i++) + { + newArray[i] = new T(); + } + + Interlocked.Exchange(ref _pool, newArray); + } + + public void Clear() + { + _poolUsed = -1; + } + } +} |
