HLSF use long as aloloc size
This commit is contained in:
@@ -1,194 +1,194 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="BidirectionalDictionary"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class BidirectionalDictionary<TFirst, TSecond> : IBidirectionalDictionary<TFirst, TSecond>
|
||||
where TFirst: notnull
|
||||
where TSecond: notnull
|
||||
{
|
||||
|
||||
private readonly Dictionary<TFirst, TSecond> _forward;
|
||||
private readonly Dictionary<TSecond, TFirst> _reverse;
|
||||
|
||||
public BidirectionalDictionary()
|
||||
{
|
||||
_forward = [];
|
||||
_reverse = [];
|
||||
}
|
||||
|
||||
public TFirst this[TSecond key]
|
||||
{
|
||||
get => _reverse.TryGetValue(key, out TFirst value) ?
|
||||
value :
|
||||
throw new ArgumentException($"Cannot find key {key} in dictionary.");
|
||||
set
|
||||
{
|
||||
if (_reverse.TryGetValue(key, out TFirst origin))
|
||||
{
|
||||
_reverse[key] = value;
|
||||
_ = _forward.Remove(origin);
|
||||
} else
|
||||
{
|
||||
_reverse.Add(key, value);
|
||||
}
|
||||
_forward.Add(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
public TSecond this[TFirst key]
|
||||
{
|
||||
get => _forward.TryGetValue(key, out TSecond value) ?
|
||||
value :
|
||||
throw new ArgumentException($"Cannot find key {key} in dictionary.");
|
||||
set
|
||||
{
|
||||
if (_forward.TryGetValue(key, out TSecond origin))
|
||||
{
|
||||
_forward[key] = value;
|
||||
_ = _reverse.Remove(origin);
|
||||
} else
|
||||
{
|
||||
_forward.Add(key, value);
|
||||
}
|
||||
_reverse.Add(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public ICollection<TFirst> FirstIndex => _forward.Keys;
|
||||
|
||||
public ICollection<TSecond> SecondIndex => _reverse.Keys;
|
||||
|
||||
public int Count => _forward.Count;
|
||||
|
||||
public IReadOnlyDictionary<TFirst, TSecond> Forward => new ReadOnlyDictionary<TFirst, TSecond>(
|
||||
_forward);
|
||||
|
||||
public IReadOnlyDictionary<TSecond, TFirst> Reverse => new ReadOnlyDictionary<TSecond, TFirst>(
|
||||
_reverse);
|
||||
|
||||
public void Add(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
if (_forward.ContainsKey(item.Key) || _reverse.ContainsKey(item.Value)) {
|
||||
throw new ArgumentException("Duplicate key or value.");
|
||||
}
|
||||
_forward.Add(item.Key, item.Value);
|
||||
_reverse.Add(item.Value, item.Key);
|
||||
}
|
||||
|
||||
public void Add(TFirst key, TSecond value)
|
||||
{
|
||||
if (_forward.ContainsKey(key) || _reverse.ContainsKey(value)) {
|
||||
throw new ArgumentException("Duplicate key or value.");
|
||||
}
|
||||
_forward.Add(key, value);
|
||||
_reverse.Add(value, key);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_forward.Clear();
|
||||
_reverse.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
return _forward.Contains(item) && _reverse.TryGetValue(item.Value, out TFirst var) && var!.Equals(item.Key);
|
||||
}
|
||||
|
||||
public bool Contains(TSecond key)
|
||||
{
|
||||
return _reverse.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool Contains(TFirst key)
|
||||
{
|
||||
return _forward.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TFirst, TSecond>[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) {
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
if (arrayIndex < 0 || arrayIndex > array.Length) {
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
}
|
||||
if (array.Length - arrayIndex < _forward.Count) {
|
||||
throw new ArgumentException("The array is too small to copy the elements.");
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<TFirst, TSecond> pair in _forward) {
|
||||
array[arrayIndex++] = pair;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TFirst, TSecond>> GetEnumerator()
|
||||
{
|
||||
foreach (KeyValuePair<TFirst, TSecond> pair in _forward) {
|
||||
yield return pair;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TFirst key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
if (_forward.Remove(item.Key)) {
|
||||
return _reverse.Remove(item.Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetValue(TFirst key, out TSecond value)
|
||||
{
|
||||
return _forward.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TSecond key, out TFirst value)
|
||||
{
|
||||
return _reverse.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="BidirectionalDictionary"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class BidirectionalDictionary<TFirst, TSecond> : IBidirectionalDictionary<TFirst, TSecond>
|
||||
where TFirst: notnull
|
||||
where TSecond: notnull
|
||||
{
|
||||
|
||||
private readonly Dictionary<TFirst, TSecond> _forward;
|
||||
private readonly Dictionary<TSecond, TFirst> _reverse;
|
||||
|
||||
public BidirectionalDictionary()
|
||||
{
|
||||
_forward = [];
|
||||
_reverse = [];
|
||||
}
|
||||
|
||||
public TFirst this[TSecond key]
|
||||
{
|
||||
get => _reverse.TryGetValue(key, out TFirst value) ?
|
||||
value :
|
||||
throw new ArgumentException($"Cannot find key {key} in dictionary.");
|
||||
set
|
||||
{
|
||||
if (_reverse.TryGetValue(key, out TFirst origin))
|
||||
{
|
||||
_reverse[key] = value;
|
||||
_ = _forward.Remove(origin);
|
||||
} else
|
||||
{
|
||||
_reverse.Add(key, value);
|
||||
}
|
||||
_forward.Add(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
public TSecond this[TFirst key]
|
||||
{
|
||||
get => _forward.TryGetValue(key, out TSecond value) ?
|
||||
value :
|
||||
throw new ArgumentException($"Cannot find key {key} in dictionary.");
|
||||
set
|
||||
{
|
||||
if (_forward.TryGetValue(key, out TSecond origin))
|
||||
{
|
||||
_forward[key] = value;
|
||||
_ = _reverse.Remove(origin);
|
||||
} else
|
||||
{
|
||||
_forward.Add(key, value);
|
||||
}
|
||||
_reverse.Add(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public ICollection<TFirst> FirstIndex => _forward.Keys;
|
||||
|
||||
public ICollection<TSecond> SecondIndex => _reverse.Keys;
|
||||
|
||||
public int Count => _forward.Count;
|
||||
|
||||
public IReadOnlyDictionary<TFirst, TSecond> Forward => new ReadOnlyDictionary<TFirst, TSecond>(
|
||||
_forward);
|
||||
|
||||
public IReadOnlyDictionary<TSecond, TFirst> Reverse => new ReadOnlyDictionary<TSecond, TFirst>(
|
||||
_reverse);
|
||||
|
||||
public void Add(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
if (_forward.ContainsKey(item.Key) || _reverse.ContainsKey(item.Value)) {
|
||||
throw new ArgumentException("Duplicate key or value.");
|
||||
}
|
||||
_forward.Add(item.Key, item.Value);
|
||||
_reverse.Add(item.Value, item.Key);
|
||||
}
|
||||
|
||||
public void Add(TFirst key, TSecond value)
|
||||
{
|
||||
if (_forward.ContainsKey(key) || _reverse.ContainsKey(value)) {
|
||||
throw new ArgumentException("Duplicate key or value.");
|
||||
}
|
||||
_forward.Add(key, value);
|
||||
_reverse.Add(value, key);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_forward.Clear();
|
||||
_reverse.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
return _forward.Contains(item) && _reverse.TryGetValue(item.Value, out TFirst var) && var!.Equals(item.Key);
|
||||
}
|
||||
|
||||
public bool Contains(TSecond key)
|
||||
{
|
||||
return _reverse.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool Contains(TFirst key)
|
||||
{
|
||||
return _forward.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TFirst, TSecond>[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) {
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
if (arrayIndex < 0 || arrayIndex > array.Length) {
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
}
|
||||
if (array.Length - arrayIndex < _forward.Count) {
|
||||
throw new ArgumentException("The array is too small to copy the elements.");
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<TFirst, TSecond> pair in _forward) {
|
||||
array[arrayIndex++] = pair;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TFirst, TSecond>> GetEnumerator()
|
||||
{
|
||||
foreach (KeyValuePair<TFirst, TSecond> pair in _forward) {
|
||||
yield return pair;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TFirst key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TFirst, TSecond> item)
|
||||
{
|
||||
if (_forward.Remove(item.Key)) {
|
||||
return _reverse.Remove(item.Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetValue(TFirst key, out TSecond value)
|
||||
{
|
||||
return _forward.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TSecond key, out TFirst value)
|
||||
{
|
||||
return _reverse.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,92 +1,92 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedBag"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class CapacityFixedBag<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly T[] _buffer;
|
||||
|
||||
public CapacityFixedBag(int capacity)
|
||||
{
|
||||
_buffer = new T[capacity];
|
||||
}
|
||||
|
||||
public int Count { get; set; }
|
||||
|
||||
public int Capacity => _buffer.Length;
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (Count >= _buffer.Length) {
|
||||
throw new InvalidOperationException("Bag capacity exceeded.");
|
||||
}
|
||||
_buffer[Count] = item;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < Count; i++) {
|
||||
yield return _buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(T item)
|
||||
{
|
||||
int index = Array.IndexOf(_buffer, item, 0, Count);
|
||||
if (index >= 0)
|
||||
{
|
||||
_buffer[index] = _buffer[Count - 1];
|
||||
_buffer[Count - 1] = default!;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
_buffer[index] = _buffer[Count - 1];
|
||||
_buffer[Count - 1] = default!;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedBag"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class CapacityFixedBag<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly T[] _buffer;
|
||||
|
||||
public CapacityFixedBag(int capacity)
|
||||
{
|
||||
_buffer = new T[capacity];
|
||||
}
|
||||
|
||||
public int Count { get; set; }
|
||||
|
||||
public int Capacity => _buffer.Length;
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (Count >= _buffer.Length) {
|
||||
throw new InvalidOperationException("Bag capacity exceeded.");
|
||||
}
|
||||
_buffer[Count] = item;
|
||||
Count++;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < Count; i++) {
|
||||
yield return _buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(T item)
|
||||
{
|
||||
int index = Array.IndexOf(_buffer, item, 0, Count);
|
||||
if (index >= 0)
|
||||
{
|
||||
_buffer[index] = _buffer[Count - 1];
|
||||
_buffer[Count - 1] = default!;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
_buffer[index] = _buffer[Count - 1];
|
||||
_buffer[Count - 1] = default!;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +1,183 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedList"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public static class CapacityFixedListBuilder
|
||||
{
|
||||
|
||||
internal static CapacityFixedList<T> Create<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
return new CapacityFixedList<T>(values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[CollectionBuilder(typeof(CapacityFixedListBuilder), nameof(CapacityFixedListBuilder.Create))]
|
||||
public class CapacityFixedList<T> : IList<T>
|
||||
{
|
||||
|
||||
private T[] _values;
|
||||
private int capacity, _index;
|
||||
|
||||
public CapacityFixedList(int size)
|
||||
{
|
||||
_values = new T[size];
|
||||
}
|
||||
|
||||
public CapacityFixedList(ReadOnlySpan<T> values)
|
||||
{
|
||||
_values = values.ToArray();
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get => index < _index ? _values[index] : throw new ArgumentOutOfRangeException(nameof(index));
|
||||
set
|
||||
{
|
||||
if (index < _index)
|
||||
{
|
||||
_values[index] = value;
|
||||
} else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int Count => _index + 1;
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (_index < capacity - 1)
|
||||
{
|
||||
_index++;
|
||||
this[_index] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_values = new T[capacity];
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if (item.Equals(_values[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
_values.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i <= _index; i++) {
|
||||
yield return _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
T v;
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if ((v = _values[i]) != null && v.Equals(item)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
T v;
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if ((v = _values[i]) != null && v.Equals(item))
|
||||
{
|
||||
_values[i] = _values[_index];
|
||||
_index--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoveAll(Predicate<T> predicate)
|
||||
{
|
||||
for (int i = _index; i > 0; i--)
|
||||
{
|
||||
if (predicate(_values[i]))
|
||||
{
|
||||
_values[i] = _values[_index];
|
||||
_index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index <= _index)
|
||||
{
|
||||
_values[index] = _values[_index];
|
||||
_index--;
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(int newSize)
|
||||
{
|
||||
Array.Resize(ref _values, newSize);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
yield return GetEnumerator();
|
||||
}
|
||||
|
||||
void IList<T>.Insert(int index, T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
}//------------------------------------- End of Class ------------------------------------------
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedList"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public static class CapacityFixedListBuilder
|
||||
{
|
||||
|
||||
internal static CapacityFixedList<T> Create<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
return new CapacityFixedList<T>(values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[CollectionBuilder(typeof(CapacityFixedListBuilder), nameof(CapacityFixedListBuilder.Create))]
|
||||
public class CapacityFixedList<T> : IList<T>
|
||||
{
|
||||
|
||||
private T[] _values;
|
||||
private int capacity, _index;
|
||||
|
||||
public CapacityFixedList(int size)
|
||||
{
|
||||
_values = new T[size];
|
||||
}
|
||||
|
||||
public CapacityFixedList(ReadOnlySpan<T> values)
|
||||
{
|
||||
_values = values.ToArray();
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get => index < _index ? _values[index] : throw new ArgumentOutOfRangeException(nameof(index));
|
||||
set
|
||||
{
|
||||
if (index < _index)
|
||||
{
|
||||
_values[index] = value;
|
||||
} else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public int Count => _index + 1;
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (_index < capacity - 1)
|
||||
{
|
||||
_index++;
|
||||
this[_index] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_values = new T[capacity];
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if (item.Equals(_values[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
_values.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i <= _index; i++) {
|
||||
yield return _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
T v;
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if ((v = _values[i]) != null && v.Equals(item)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
T v;
|
||||
for (int i = 0; i <= _index; i++)
|
||||
{
|
||||
if ((v = _values[i]) != null && v.Equals(item))
|
||||
{
|
||||
_values[i] = _values[_index];
|
||||
_index--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoveAll(Predicate<T> predicate)
|
||||
{
|
||||
for (int i = _index; i > 0; i--)
|
||||
{
|
||||
if (predicate(_values[i]))
|
||||
{
|
||||
_values[i] = _values[_index];
|
||||
_index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index <= _index)
|
||||
{
|
||||
_values[index] = _values[_index];
|
||||
_index--;
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(int newSize)
|
||||
{
|
||||
Array.Resize(ref _values, newSize);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
yield return GetEnumerator();
|
||||
}
|
||||
|
||||
void IList<T>.Insert(int index, T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
}//------------------------------------- End of Class ------------------------------------------
|
||||
}
|
||||
|
||||
@@ -1,170 +1,170 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
[CollectionBuilder(typeof(CapacityFixedStackBuilder), nameof(CapacityFixedStackBuilder.Create))]
|
||||
public class CapacityFixedStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly T[] _values;
|
||||
|
||||
// _index points to the next free slot (top empty position). Therefore Count == _index.
|
||||
private int _index;
|
||||
|
||||
public CapacityFixedStack(int size)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(size);
|
||||
_values = new T[size];
|
||||
_index = 0; // empty stack
|
||||
}
|
||||
|
||||
public T? First => Volatile.Read(ref _index) > 0 ? _values[0] : default;
|
||||
|
||||
public bool IsEmpty => Volatile.Read(ref _index) == 0;
|
||||
|
||||
public int Count => Volatile.Read(ref _index);
|
||||
|
||||
public int Capacity => _values.Length;
|
||||
|
||||
public ReadOnlySpan<T> AsSpan() => _values.AsSpan(0, _index);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (_index > 0)
|
||||
{
|
||||
Array.Clear(_values, 0, _index);
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = _index - 1; i >= 0; i--) {
|
||||
yield return _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (_index == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
return _values[_index - 1];
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (_index == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
_index--;
|
||||
T item = _values[_index];
|
||||
_values[_index] = default!; // Clear reference for GC
|
||||
return item;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T[] PopRange(int count)
|
||||
{
|
||||
if (count <= 0 || _index == 0) {
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
int n = Math.Min(count, _index);
|
||||
int start = _index - n;
|
||||
T[] ret = new T[n];
|
||||
Array.Copy(_values, start, ret, 0, n);
|
||||
Array.Clear(_values, start, n);
|
||||
_index -= n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
if (_index >= _values.Length) {
|
||||
throw new InvalidOperationException("Stack is full.");
|
||||
}
|
||||
_values[_index] = item;
|
||||
_index++;
|
||||
}
|
||||
|
||||
public void PushRange(ReadOnlySpan<T> span)
|
||||
{
|
||||
if (span.Length == 0) {
|
||||
return;
|
||||
}
|
||||
if (_index + span.Length > _values.Length) {
|
||||
throw new InvalidOperationException("Not enough space in the stack to push the entire span.");
|
||||
}
|
||||
span.CopyTo(_values.AsSpan(_index, span.Length));
|
||||
_index += span.Length;
|
||||
}
|
||||
|
||||
public bool TryPop(out T value)
|
||||
{
|
||||
if (_index == 0)
|
||||
{
|
||||
value = default!;
|
||||
return false;
|
||||
}
|
||||
_index--;
|
||||
value = _values[_index];
|
||||
_values[_index] = default!;
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal Span<T> GetValueLayout()
|
||||
{
|
||||
return _values.AsSpan();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class CapacityFixedStackBuilder
|
||||
{
|
||||
|
||||
public static CapacityFixedStack<T> Create<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
CapacityFixedStack<T> stack = new(values.Length);
|
||||
stack.PushRange(values); // Push in order
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="CapacityFixedStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
[CollectionBuilder(typeof(CapacityFixedStackBuilder), nameof(CapacityFixedStackBuilder.Create))]
|
||||
public class CapacityFixedStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly T[] _values;
|
||||
|
||||
// _index points to the next free slot (top empty position). Therefore Count == _index.
|
||||
private int _index;
|
||||
|
||||
public CapacityFixedStack(int size)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(size);
|
||||
_values = new T[size];
|
||||
_index = 0; // empty stack
|
||||
}
|
||||
|
||||
public T? First => Volatile.Read(ref _index) > 0 ? _values[0] : default;
|
||||
|
||||
public bool IsEmpty => Volatile.Read(ref _index) == 0;
|
||||
|
||||
public int Count => Volatile.Read(ref _index);
|
||||
|
||||
public int Capacity => _values.Length;
|
||||
|
||||
public ReadOnlySpan<T> AsSpan() => _values.AsSpan(0, _index);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (_index > 0)
|
||||
{
|
||||
Array.Clear(_values, 0, _index);
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = _index - 1; i >= 0; i--) {
|
||||
yield return _values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (_index == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
return _values[_index - 1];
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (_index == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
_index--;
|
||||
T item = _values[_index];
|
||||
_values[_index] = default!; // Clear reference for GC
|
||||
return item;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T[] PopRange(int count)
|
||||
{
|
||||
if (count <= 0 || _index == 0) {
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
int n = Math.Min(count, _index);
|
||||
int start = _index - n;
|
||||
T[] ret = new T[n];
|
||||
Array.Copy(_values, start, ret, 0, n);
|
||||
Array.Clear(_values, start, n);
|
||||
_index -= n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
if (_index >= _values.Length) {
|
||||
throw new InvalidOperationException("Stack is full.");
|
||||
}
|
||||
_values[_index] = item;
|
||||
_index++;
|
||||
}
|
||||
|
||||
public void PushRange(ReadOnlySpan<T> span)
|
||||
{
|
||||
if (span.Length == 0) {
|
||||
return;
|
||||
}
|
||||
if (_index + span.Length > _values.Length) {
|
||||
throw new InvalidOperationException("Not enough space in the stack to push the entire span.");
|
||||
}
|
||||
span.CopyTo(_values.AsSpan(_index, span.Length));
|
||||
_index += span.Length;
|
||||
}
|
||||
|
||||
public bool TryPop(out T value)
|
||||
{
|
||||
if (_index == 0)
|
||||
{
|
||||
value = default!;
|
||||
return false;
|
||||
}
|
||||
_index--;
|
||||
value = _values[_index];
|
||||
_values[_index] = default!;
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal Span<T> GetValueLayout()
|
||||
{
|
||||
return _values.AsSpan();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class CapacityFixedStackBuilder
|
||||
{
|
||||
|
||||
public static CapacityFixedStack<T> Create<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
CapacityFixedStack<T> stack = new(values.Length);
|
||||
stack.PushRange(values); // Push in order
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,287 +1,287 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="ConcurrentCapacityFixedStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload Space
|
||||
// Copyright (c) Nitload Space. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Lock-free, fixed-capacity stack implemented on top of an array using atomic index
|
||||
/// operations. - No linked list; only array slots - Uses CAS on a shared top index to
|
||||
/// reserve/release slots - Per-slot state flag to safely publish/consume values under races
|
||||
/// </summary>
|
||||
public class ConcurrentCapacityFixedStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly int[] _states; // 0 = empty, 1 = full
|
||||
private readonly T[] _values;
|
||||
private readonly int _capacity;
|
||||
|
||||
// Number of full slots (observable count)
|
||||
private int _count;
|
||||
|
||||
// Next push position (0.._capacity). Only modified via CAS.
|
||||
private int _top;
|
||||
|
||||
public ConcurrentCapacityFixedStack(int capacity)
|
||||
{
|
||||
if (capacity <= 0) {
|
||||
throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||
}
|
||||
|
||||
_capacity = capacity;
|
||||
_values = new T[capacity];
|
||||
_states = new int[capacity];
|
||||
_top = 0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public bool IsEmpty => Count == 0;
|
||||
|
||||
public int Capacity => _capacity;
|
||||
|
||||
public int Count => Volatile.Read(ref _count);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
// Pop all elements to return slots to empty state
|
||||
while (TryPop(out _)) { }
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
T[] snap = ToArraySnapshot();
|
||||
for (int i = 0; i < snap.Length; i++) {
|
||||
yield return snap[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (TryPeek(out T? v)) {
|
||||
return v;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (TryPop(out T value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
public T[] PopRange(int count)
|
||||
{
|
||||
if (count <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
T[] result = new T[count];
|
||||
int i = 0;
|
||||
for (; i < count; i++)
|
||||
{
|
||||
if (!TryPop(out result[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == count) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
T[] trimmed = new T[i];
|
||||
Array.Copy(result, trimmed, i);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
SpinWait sw = default;
|
||||
while (true)
|
||||
{
|
||||
int oldTop = Volatile.Read(ref _top);
|
||||
if (oldTop >= _capacity) {
|
||||
throw new InvalidOperationException("Stack is full.");
|
||||
}
|
||||
|
||||
if (Interlocked.CompareExchange(ref _top, oldTop + 1, oldTop) != oldTop)
|
||||
{
|
||||
sw.SpinOnce();
|
||||
continue; // failed to reserve slot
|
||||
}
|
||||
|
||||
// We exclusively own slot oldTop. Publish value then state.
|
||||
_values[oldTop] = item;
|
||||
Volatile.Write(ref _states[oldTop], 1); // publish
|
||||
_ = Interlocked.Increment(ref _count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void PushRange(ReadOnlySpan<T> span)
|
||||
{
|
||||
for (int i = 0; i < span.Length; i++) {
|
||||
Push(span[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Best-effort snapshot for enumeration; not strongly consistent under concurrent
|
||||
/// mutations.
|
||||
/// </summary>
|
||||
public T[] ToArraySnapshot()
|
||||
{
|
||||
int expected = Math.Min(Volatile.Read(ref _count), _capacity);
|
||||
if (expected == 0) {
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
|
||||
T[] snap = new T[expected];
|
||||
int copied = 0;
|
||||
int idx = Volatile.Read(ref _top) - 1;
|
||||
while (idx >= 0 && copied < expected)
|
||||
{
|
||||
if (Volatile.Read(ref _states[idx]) == 1) {
|
||||
snap[copied++] = _values[idx];
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (copied == snap.Length) {
|
||||
return snap;
|
||||
}
|
||||
|
||||
T[] trimmed = new T[copied];
|
||||
Array.Copy(snap, trimmed, copied);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public bool TryPeek(out T value)
|
||||
{
|
||||
value = default!;
|
||||
SpinWait sw = default;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int top = Volatile.Read(ref _top);
|
||||
if (top <= 0) {
|
||||
return false;
|
||||
}
|
||||
int idx = top - 1;
|
||||
|
||||
// If not yet published or racing, retry/spin
|
||||
if (Volatile.Read(ref _states[idx]) == 0)
|
||||
{
|
||||
if (Volatile.Read(ref _top) != top)
|
||||
{
|
||||
continue; // head moved, retry
|
||||
}
|
||||
sw.SpinOnce();
|
||||
continue;
|
||||
}
|
||||
|
||||
T v = _values[idx];
|
||||
|
||||
// Validate consistency
|
||||
if (Volatile.Read(ref _top) == top && Volatile.Read(ref _states[idx]) == 1)
|
||||
{
|
||||
value = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryPop(out T value)
|
||||
{
|
||||
value = default!;
|
||||
SpinWait sw = default;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int oldTop = Volatile.Read(ref _top);
|
||||
if (oldTop <= 0)
|
||||
{
|
||||
return false; // empty
|
||||
}
|
||||
|
||||
int newTop = oldTop - 1; // index to consume
|
||||
if (Interlocked.CompareExchange(ref _top, newTop, oldTop) != oldTop)
|
||||
{
|
||||
sw.SpinOnce();
|
||||
continue; // failed to reserve element
|
||||
}
|
||||
|
||||
// If producer hasn't published yet, roll back our reservation and retry.
|
||||
if (Volatile.Read(ref _states[newTop]) == 0)
|
||||
{
|
||||
// attempt to restore top; ok if it fails due to concurrent operations
|
||||
_ = Interlocked.CompareExchange(ref _top, newTop + 1, newTop);
|
||||
sw.SpinOnce();
|
||||
continue;
|
||||
}
|
||||
|
||||
value = _values[newTop];
|
||||
_values[newTop] = default!; // avoid ref retention
|
||||
Volatile.Write(ref _states[newTop], 0); // mark empty
|
||||
_ = Interlocked.Decrement(ref _count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int TryPopRange(Span<T> destination)
|
||||
{
|
||||
if (destination.IsEmpty) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (; i < destination.Length; i++)
|
||||
{
|
||||
if (!TryPop(out destination[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="ConcurrentCapacityFixedStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload Space
|
||||
// Copyright (c) Nitload Space. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Lock-free, fixed-capacity stack implemented on top of an array using atomic index
|
||||
/// operations. - No linked list; only array slots - Uses CAS on a shared top index to
|
||||
/// reserve/release slots - Per-slot state flag to safely publish/consume values under races
|
||||
/// </summary>
|
||||
public class ConcurrentCapacityFixedStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private readonly int[] _states; // 0 = empty, 1 = full
|
||||
private readonly T[] _values;
|
||||
private readonly int _capacity;
|
||||
|
||||
// Number of full slots (observable count)
|
||||
private int _count;
|
||||
|
||||
// Next push position (0.._capacity). Only modified via CAS.
|
||||
private int _top;
|
||||
|
||||
public ConcurrentCapacityFixedStack(int capacity)
|
||||
{
|
||||
if (capacity <= 0) {
|
||||
throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||
}
|
||||
|
||||
_capacity = capacity;
|
||||
_values = new T[capacity];
|
||||
_states = new int[capacity];
|
||||
_top = 0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public bool IsEmpty => Count == 0;
|
||||
|
||||
public int Capacity => _capacity;
|
||||
|
||||
public int Count => Volatile.Read(ref _count);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
// Pop all elements to return slots to empty state
|
||||
while (TryPop(out _)) { }
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
T[] snap = ToArraySnapshot();
|
||||
for (int i = 0; i < snap.Length; i++) {
|
||||
yield return snap[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (TryPeek(out T? v)) {
|
||||
return v;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (TryPop(out T value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
public T[] PopRange(int count)
|
||||
{
|
||||
if (count <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
T[] result = new T[count];
|
||||
int i = 0;
|
||||
for (; i < count; i++)
|
||||
{
|
||||
if (!TryPop(out result[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == count) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
T[] trimmed = new T[i];
|
||||
Array.Copy(result, trimmed, i);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
SpinWait sw = default;
|
||||
while (true)
|
||||
{
|
||||
int oldTop = Volatile.Read(ref _top);
|
||||
if (oldTop >= _capacity) {
|
||||
throw new InvalidOperationException("Stack is full.");
|
||||
}
|
||||
|
||||
if (Interlocked.CompareExchange(ref _top, oldTop + 1, oldTop) != oldTop)
|
||||
{
|
||||
sw.SpinOnce();
|
||||
continue; // failed to reserve slot
|
||||
}
|
||||
|
||||
// We exclusively own slot oldTop. Publish value then state.
|
||||
_values[oldTop] = item;
|
||||
Volatile.Write(ref _states[oldTop], 1); // publish
|
||||
_ = Interlocked.Increment(ref _count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void PushRange(ReadOnlySpan<T> span)
|
||||
{
|
||||
for (int i = 0; i < span.Length; i++) {
|
||||
Push(span[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Best-effort snapshot for enumeration; not strongly consistent under concurrent
|
||||
/// mutations.
|
||||
/// </summary>
|
||||
public T[] ToArraySnapshot()
|
||||
{
|
||||
int expected = Math.Min(Volatile.Read(ref _count), _capacity);
|
||||
if (expected == 0) {
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
|
||||
T[] snap = new T[expected];
|
||||
int copied = 0;
|
||||
int idx = Volatile.Read(ref _top) - 1;
|
||||
while (idx >= 0 && copied < expected)
|
||||
{
|
||||
if (Volatile.Read(ref _states[idx]) == 1) {
|
||||
snap[copied++] = _values[idx];
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (copied == snap.Length) {
|
||||
return snap;
|
||||
}
|
||||
|
||||
T[] trimmed = new T[copied];
|
||||
Array.Copy(snap, trimmed, copied);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public bool TryPeek(out T value)
|
||||
{
|
||||
value = default!;
|
||||
SpinWait sw = default;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int top = Volatile.Read(ref _top);
|
||||
if (top <= 0) {
|
||||
return false;
|
||||
}
|
||||
int idx = top - 1;
|
||||
|
||||
// If not yet published or racing, retry/spin
|
||||
if (Volatile.Read(ref _states[idx]) == 0)
|
||||
{
|
||||
if (Volatile.Read(ref _top) != top)
|
||||
{
|
||||
continue; // head moved, retry
|
||||
}
|
||||
sw.SpinOnce();
|
||||
continue;
|
||||
}
|
||||
|
||||
T v = _values[idx];
|
||||
|
||||
// Validate consistency
|
||||
if (Volatile.Read(ref _top) == top && Volatile.Read(ref _states[idx]) == 1)
|
||||
{
|
||||
value = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryPop(out T value)
|
||||
{
|
||||
value = default!;
|
||||
SpinWait sw = default;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int oldTop = Volatile.Read(ref _top);
|
||||
if (oldTop <= 0)
|
||||
{
|
||||
return false; // empty
|
||||
}
|
||||
|
||||
int newTop = oldTop - 1; // index to consume
|
||||
if (Interlocked.CompareExchange(ref _top, newTop, oldTop) != oldTop)
|
||||
{
|
||||
sw.SpinOnce();
|
||||
continue; // failed to reserve element
|
||||
}
|
||||
|
||||
// If producer hasn't published yet, roll back our reservation and retry.
|
||||
if (Volatile.Read(ref _states[newTop]) == 0)
|
||||
{
|
||||
// attempt to restore top; ok if it fails due to concurrent operations
|
||||
_ = Interlocked.CompareExchange(ref _top, newTop + 1, newTop);
|
||||
sw.SpinOnce();
|
||||
continue;
|
||||
}
|
||||
|
||||
value = _values[newTop];
|
||||
_values[newTop] = default!; // avoid ref retention
|
||||
Volatile.Write(ref _states[newTop], 0); // mark empty
|
||||
_ = Interlocked.Decrement(ref _count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int TryPopRange(Span<T> destination)
|
||||
{
|
||||
if (destination.IsEmpty) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (; i < destination.Length; i++)
|
||||
{
|
||||
if (!TryPop(out destination[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,95 +1,84 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="IBidirectionalDictionary"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public interface IBidirectionalDictionary<TFirst, TSecond> : IDictionary<TFirst, TSecond>
|
||||
{
|
||||
|
||||
TFirst this[
|
||||
TSecond key
|
||||
] { get; set; }
|
||||
|
||||
ICollection<TFirst> FirstIndex { get; }
|
||||
|
||||
ICollection<TSecond> SecondIndex { get; }
|
||||
|
||||
IReadOnlyDictionary<TFirst, TSecond> Forward { get; }
|
||||
|
||||
IReadOnlyDictionary<TSecond, TFirst> Reverse { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains the
|
||||
/// specified key.
|
||||
/// </summary>
|
||||
/// <param _label="key">
|
||||
/// The value to locate in the <see cref="IBidirectionalDictionary{TFirst, TSecond}" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains an element with
|
||||
/// the specified key; otherwise, false.
|
||||
/// </returns>
|
||||
bool Contains(
|
||||
TSecond key
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains the
|
||||
/// specified key.
|
||||
/// </summary>
|
||||
/// <param _label="key">
|
||||
/// The value to locate in the <see cref="IBidirectionalDictionary{TFirst, TSecond}" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains an element with
|
||||
/// the specified key; otherwise, false.
|
||||
/// </returns>
|
||||
bool Contains(
|
||||
TFirst key
|
||||
);
|
||||
|
||||
bool TryGetValue(
|
||||
TSecond key,
|
||||
out TFirst value
|
||||
);
|
||||
|
||||
#pragma warning disable CA1033
|
||||
ICollection<TFirst> IDictionary<TFirst, TSecond>.Keys => FirstIndex;
|
||||
|
||||
ICollection<TSecond> IDictionary<TFirst, TSecond>.Values => SecondIndex;
|
||||
|
||||
bool IDictionary<TFirst, TSecond>.ContainsKey(
|
||||
TFirst key
|
||||
)
|
||||
{
|
||||
return Contains(key);
|
||||
}
|
||||
#pragma warning restore CA1033
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="IBidirectionalDictionary"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload Space
|
||||
// Copyright (c) Nitload Space. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public interface IBidirectionalDictionary<TFirst, TSecond> : IDictionary<TFirst, TSecond>
|
||||
{
|
||||
|
||||
TFirst this[TSecond key] { get; set; }
|
||||
|
||||
ICollection<TFirst> FirstIndex { get; }
|
||||
|
||||
ICollection<TSecond> SecondIndex { get; }
|
||||
|
||||
IReadOnlyDictionary<TFirst, TSecond> Forward { get; }
|
||||
|
||||
IReadOnlyDictionary<TSecond, TFirst> Reverse { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains the
|
||||
/// specified key.
|
||||
/// </summary>
|
||||
/// <param _label="key">
|
||||
/// The value to locate in the <see cref="IBidirectionalDictionary{TFirst, TSecond}" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains an element with
|
||||
/// the specified key; otherwise, false.
|
||||
/// </returns>
|
||||
bool Contains(TSecond key);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains the
|
||||
/// specified key.
|
||||
/// </summary>
|
||||
/// <param _label="key">
|
||||
/// The value to locate in the <see cref="IBidirectionalDictionary{TFirst, TSecond}" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the <see cref="IBidirectionalDictionary{TFirst, TSecond}" /> contains an element with
|
||||
/// the specified key; otherwise, false.
|
||||
/// </returns>
|
||||
bool Contains(TFirst key);
|
||||
|
||||
bool TryGetValue(TSecond key, out TFirst value);
|
||||
|
||||
#pragma warning disable CA1033
|
||||
ICollection<TFirst> IDictionary<TFirst, TSecond>.Keys => FirstIndex;
|
||||
|
||||
ICollection<TSecond> IDictionary<TFirst, TSecond>.Values => SecondIndex;
|
||||
|
||||
bool IDictionary<TFirst, TSecond>.ContainsKey(TFirst key)
|
||||
{
|
||||
return Contains(key);
|
||||
}
|
||||
#pragma warning restore CA1033
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,53 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="IHashMultiplexer"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public interface IHashMultiplexer<T> : IEqualityComparer<T>
|
||||
{
|
||||
|
||||
int RemainedMultiplexCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache hash result for obj with counts.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
///
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
///
|
||||
/// </param>
|
||||
void CacheHash(T obj, int count);
|
||||
|
||||
void ExtendCache(int count);
|
||||
|
||||
int ForceComputeHash(T count);
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="IHashMultiplexer"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public interface IHashMultiplexer<T> : IEqualityComparer<T>
|
||||
{
|
||||
|
||||
int RemainedMultiplexCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache hash result for obj with counts.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
///
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
///
|
||||
/// </param>
|
||||
void CacheHash(T obj, int count);
|
||||
|
||||
void ExtendCache(int count);
|
||||
|
||||
int ForceComputeHash(T count);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,131 +1,131 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="ListSegment"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Part of a collection. This contains a direct reference to _origin collection, so all
|
||||
/// change to _origin collection will be reflected in this object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
///
|
||||
/// </typeparam>
|
||||
public struct ListSegment<T> : ICollection<T>
|
||||
{
|
||||
|
||||
private int _begin;
|
||||
private int _length;
|
||||
private List<T> _collection;
|
||||
|
||||
public ListSegment(List<T> collection, int begin, int length)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(collection);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(begin, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(length, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(begin + length, collection.Count);
|
||||
_collection = collection;
|
||||
_begin = begin;
|
||||
_length = length;
|
||||
}
|
||||
|
||||
public T this[int indexValue]
|
||||
{
|
||||
get
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(indexValue, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(indexValue, _length);
|
||||
return _collection[indexValue + _begin];
|
||||
}
|
||||
}
|
||||
|
||||
public T this[Index i]
|
||||
{
|
||||
get
|
||||
{
|
||||
int offset = i.IsFromEnd ? _length - i.Value : i.Value;
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(offset, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(offset, _length);
|
||||
return _collection[offset + _begin];
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
public int Count => _length;
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
int index = _collection.IndexOf(item);
|
||||
return index >= _begin && index < _length + index;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(array);
|
||||
Span<T> span = CollectionsMarshal.AsSpan<T>(_collection).Slice(_begin, _length);
|
||||
Span<T> target = new Span<T>(array, arrayIndex, _length);
|
||||
span.CopyTo(target);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = _begin; i < _length; i++) {
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void ICollection<T>.Clear()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
bool ICollection<T>.Remove(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="ListSegment"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Part of a collection. This contains a direct reference to _origin collection, so all
|
||||
/// change to _origin collection will be reflected in this object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
///
|
||||
/// </typeparam>
|
||||
public struct ListSegment<T> : ICollection<T>
|
||||
{
|
||||
|
||||
private int _begin;
|
||||
private int _length;
|
||||
private List<T> _collection;
|
||||
|
||||
public ListSegment(List<T> collection, int begin, int length)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(collection);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(begin, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(length, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(begin + length, collection.Count);
|
||||
_collection = collection;
|
||||
_begin = begin;
|
||||
_length = length;
|
||||
}
|
||||
|
||||
public T this[int indexValue]
|
||||
{
|
||||
get
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(indexValue, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(indexValue, _length);
|
||||
return _collection[indexValue + _begin];
|
||||
}
|
||||
}
|
||||
|
||||
public T this[Index i]
|
||||
{
|
||||
get
|
||||
{
|
||||
int offset = i.IsFromEnd ? _length - i.Value : i.Value;
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(offset, 0);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(offset, _length);
|
||||
return _collection[offset + _begin];
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
public int Count => _length;
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
int index = _collection.IndexOf(item);
|
||||
return index >= _begin && index < _length + index;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(array);
|
||||
Span<T> span = CollectionsMarshal.AsSpan<T>(_collection).Slice(_begin, _length);
|
||||
Span<T> target = new Span<T>(array, arrayIndex, _length);
|
||||
span.CopyTo(target);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = _begin; i < _length; i++) {
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void ICollection<T>.Clear()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
bool ICollection<T>.Remove(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +1,191 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="NotEnumerableList"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public static class LinearBagBuilder
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Build a <see cref="LinearBag{T}" /> from a read-only span. Capacity will exactly fit
|
||||
/// the input.
|
||||
/// </summary>
|
||||
public static LinearBag<T> FromSpan<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
if (values.IsEmpty) {
|
||||
return new LinearBag<T>(4);
|
||||
}
|
||||
LinearBag<T> bag = new(values.Length);
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
bag.Add(values[i]);
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A very lightweight contiguous storage structure: unordered, not enumerable by design.
|
||||
/// Provides O(1) Add and O(1) RemoveAt (by swapping with the tail). Intended for high-
|
||||
/// performance scenarios where element ordering does not matter. NOT thread-safe.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Element type.
|
||||
/// </typeparam>
|
||||
[CollectionBuilder(typeof(LinearBagBuilder), nameof(LinearBagBuilder.FromSpan))]
|
||||
public class LinearBag<T>(int capacity = 4)
|
||||
{
|
||||
|
||||
// Invariant: valid elements occupy indexes [0, Count-1]. Count is the number of live elements.
|
||||
private T[] _items = new T[Math.Max(0, capacity)];
|
||||
|
||||
/// <summary>
|
||||
/// Access element by index (0..Count-1). Throws if out of range.
|
||||
/// </summary>
|
||||
public T this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (uint)index >= (uint)Count ? throw new ArgumentOutOfRangeException(nameof(index)) : _items[index];
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
if ((uint)index >= (uint)Count) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
_items[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total allocated slots.
|
||||
/// </summary>
|
||||
public int Capacity => _items.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Number of currently stored elements (valid index range 0..Count-1).
|
||||
/// </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item (unordered). Expands internal array if needed.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(T item)
|
||||
{
|
||||
if (Count == _items.Length) {
|
||||
EnsureCapacity(Count + 1);
|
||||
}
|
||||
|
||||
_items[Count] = item;
|
||||
Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a span over the live portion of the bag (0..Count-1).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Span<T> AsSpan() => new Span<T>(_items, 0, Count);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all elements and zeroes out references to avoid retention. Count becomes 0.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(_items, 0, Count);
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fast clear: only resets Count (leaves underlying array unchanged). References are NOT
|
||||
/// released. Use only when you are certain old references can remain.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void FastClear() => Count = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of value (unordered). Does nothing if not found.
|
||||
/// </summary>
|
||||
public void Remove(T value)
|
||||
{
|
||||
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (comparer.Equals(_items[i], value))
|
||||
{
|
||||
RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes element at index by swapping the last element into its slot (unless already
|
||||
/// last). Preserves O(1) removal at cost of ordering.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if ((uint)index >= (uint)Count) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
int last = Count - 1;
|
||||
if (index != last) {
|
||||
_items[index] = _items[last];
|
||||
}
|
||||
|
||||
_items[last] = default!; // release reference / reset value
|
||||
Count = last;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures capacity is at least <paramref name="min" />. Doubles size when growing.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void EnsureCapacity(int min)
|
||||
{
|
||||
if (_items.Length >= min) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newCapacity = _items.Length == 0 ? 4 : _items.Length * 2;
|
||||
if (newCapacity < min) {
|
||||
newCapacity = min;
|
||||
}
|
||||
|
||||
Array.Resize(ref _items, newCapacity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="NotEnumerableList"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public static class LinearBagBuilder
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Build a <see cref="LinearBag{T}" /> from a read-only span. Capacity will exactly fit
|
||||
/// the input.
|
||||
/// </summary>
|
||||
public static LinearBag<T> FromSpan<T>(ReadOnlySpan<T> values)
|
||||
{
|
||||
if (values.IsEmpty) {
|
||||
return new LinearBag<T>(4);
|
||||
}
|
||||
LinearBag<T> bag = new(values.Length);
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
bag.Add(values[i]);
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A very lightweight contiguous storage structure: unordered, not enumerable by design.
|
||||
/// Provides O(1) Add and O(1) RemoveAt (by swapping with the tail). Intended for high-
|
||||
/// performance scenarios where element ordering does not matter. NOT thread-safe.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Element type.
|
||||
/// </typeparam>
|
||||
[CollectionBuilder(typeof(LinearBagBuilder), nameof(LinearBagBuilder.FromSpan))]
|
||||
public class LinearBag<T>(int capacity = 4)
|
||||
{
|
||||
|
||||
// Invariant: valid elements occupy indexes [0, Count-1]. Count is the number of live elements.
|
||||
private T[] _items = new T[Math.Max(0, capacity)];
|
||||
|
||||
/// <summary>
|
||||
/// Access element by index (0..Count-1). Throws if out of range.
|
||||
/// </summary>
|
||||
public T this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (uint)index >= (uint)Count ? throw new ArgumentOutOfRangeException(nameof(index)) : _items[index];
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
if ((uint)index >= (uint)Count) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
_items[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total allocated slots.
|
||||
/// </summary>
|
||||
public int Capacity => _items.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Number of currently stored elements (valid index range 0..Count-1).
|
||||
/// </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item (unordered). Expands internal array if needed.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(T item)
|
||||
{
|
||||
if (Count == _items.Length) {
|
||||
EnsureCapacity(Count + 1);
|
||||
}
|
||||
|
||||
_items[Count] = item;
|
||||
Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a span over the live portion of the bag (0..Count-1).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Span<T> AsSpan() => new Span<T>(_items, 0, Count);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all elements and zeroes out references to avoid retention. Count becomes 0.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(_items, 0, Count);
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fast clear: only resets Count (leaves underlying array unchanged). References are NOT
|
||||
/// released. Use only when you are certain old references can remain.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void FastClear() => Count = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of value (unordered). Does nothing if not found.
|
||||
/// </summary>
|
||||
public void Remove(T value)
|
||||
{
|
||||
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (comparer.Equals(_items[i], value))
|
||||
{
|
||||
RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes element at index by swapping the last element into its slot (unless already
|
||||
/// last). Preserves O(1) removal at cost of ordering.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if ((uint)index >= (uint)Count) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
int last = Count - 1;
|
||||
if (index != last) {
|
||||
_items[index] = _items[last];
|
||||
}
|
||||
|
||||
_items[last] = default!; // release reference / reset value
|
||||
Count = last;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures capacity is at least <paramref name="min" />. Doubles size when growing.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void EnsureCapacity(int min)
|
||||
{
|
||||
if (_items.Length >= min) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newCapacity = _items.Length == 0 ? 4 : _items.Length * 2;
|
||||
if (newCapacity < min) {
|
||||
newCapacity = min;
|
||||
}
|
||||
|
||||
Array.Resize(ref _items, newCapacity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,181 +1,181 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="RandomAccessibleStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public class RandomAccessibleStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private const int DefaultCapacity = 4;
|
||||
|
||||
private T[] _array;
|
||||
private int _size;
|
||||
private int _version;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RandomAccessStack class that is empty and has the
|
||||
/// default initial capacity.
|
||||
/// </summary>
|
||||
public RandomAccessibleStack()
|
||||
{
|
||||
_array = new T[DefaultCapacity];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RandomAccessStack class that is empty and has the
|
||||
/// specified initial capacity.
|
||||
/// </summary>
|
||||
public RandomAccessibleStack(int capacity)
|
||||
{
|
||||
if (capacity < 0) {
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(capacity), "Capacity must be non-negative.");
|
||||
}
|
||||
|
||||
_array = new T[capacity];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element at the specified index in the stack (0 = bottom, Count-1 =
|
||||
/// top).
|
||||
/// </summary>
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= _size) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
return _array[index];
|
||||
}
|
||||
/*
|
||||
set
|
||||
{
|
||||
if( index < 0 || index >= PrimSize ) {
|
||||
throw new ArgumentOutOfRangeException( nameof( index ) );
|
||||
}
|
||||
_array[ index ] = value;
|
||||
_version++;
|
||||
}
|
||||
/**/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the stack.
|
||||
/// </summary>
|
||||
public int Count => _size;
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the stack.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(_array, 0, _size);
|
||||
_size = 0;
|
||||
_version++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the stack from top to bottom. Throws if
|
||||
/// the stack is modified during iteration.
|
||||
/// </summary>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
int expectedVersion = _version;
|
||||
for (int i = _size - 1; i >= 0; i--)
|
||||
{
|
||||
if (expectedVersion != _version) {
|
||||
throw new InvalidOperationException(
|
||||
"Collection was modified during enumeration.");
|
||||
}
|
||||
|
||||
yield return _array[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the object at the top of the stack without removing it.
|
||||
/// </summary>
|
||||
public T Peek()
|
||||
{
|
||||
if (_size == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
return _array[_size - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes and returns the object at the top of the stack.
|
||||
/// </summary>
|
||||
public T Pop()
|
||||
{
|
||||
if (_size == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
T item = _array[--_size];
|
||||
_array[_size] = default!;
|
||||
_version++;
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the top of the stack.
|
||||
/// </summary>
|
||||
public void Push(T item)
|
||||
{
|
||||
if (_size == _array.Length) {
|
||||
EnsureCapacity(_size + 1);
|
||||
}
|
||||
|
||||
_array[_size++] = item;
|
||||
_version++;
|
||||
}
|
||||
|
||||
private void EnsureCapacity(int min)
|
||||
{
|
||||
int newCapacity = _array.Length == 0 ? DefaultCapacity : _array.Length * 2;
|
||||
if (newCapacity < min) {
|
||||
newCapacity = min;
|
||||
}
|
||||
|
||||
Array.Resize(ref _array, newCapacity);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="RandomAccessibleStack"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public class RandomAccessibleStack<T> : IEnumerable<T>
|
||||
{
|
||||
|
||||
private const int DefaultCapacity = 4;
|
||||
|
||||
private T[] _array;
|
||||
private int _size;
|
||||
private int _version;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RandomAccessStack class that is empty and has the
|
||||
/// default initial capacity.
|
||||
/// </summary>
|
||||
public RandomAccessibleStack()
|
||||
{
|
||||
_array = new T[DefaultCapacity];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RandomAccessStack class that is empty and has the
|
||||
/// specified initial capacity.
|
||||
/// </summary>
|
||||
public RandomAccessibleStack(int capacity)
|
||||
{
|
||||
if (capacity < 0) {
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(capacity), "Capacity must be non-negative.");
|
||||
}
|
||||
|
||||
_array = new T[capacity];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element at the specified index in the stack (0 = bottom, Count-1 =
|
||||
/// top).
|
||||
/// </summary>
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= _size) {
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
return _array[index];
|
||||
}
|
||||
/*
|
||||
set
|
||||
{
|
||||
if( index < 0 || index >= PrimSize ) {
|
||||
throw new ArgumentOutOfRangeException( nameof( index ) );
|
||||
}
|
||||
_array[ index ] = value;
|
||||
_version++;
|
||||
}
|
||||
/**/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the stack.
|
||||
/// </summary>
|
||||
public int Count => _size;
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the stack.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(_array, 0, _size);
|
||||
_size = 0;
|
||||
_version++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the stack from top to bottom. Throws if
|
||||
/// the stack is modified during iteration.
|
||||
/// </summary>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
int expectedVersion = _version;
|
||||
for (int i = _size - 1; i >= 0; i--)
|
||||
{
|
||||
if (expectedVersion != _version) {
|
||||
throw new InvalidOperationException(
|
||||
"Collection was modified during enumeration.");
|
||||
}
|
||||
|
||||
yield return _array[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the object at the top of the stack without removing it.
|
||||
/// </summary>
|
||||
public T Peek()
|
||||
{
|
||||
if (_size == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
return _array[_size - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes and returns the object at the top of the stack.
|
||||
/// </summary>
|
||||
public T Pop()
|
||||
{
|
||||
if (_size == 0) {
|
||||
throw new InvalidOperationException("Stack is empty.");
|
||||
}
|
||||
|
||||
T item = _array[--_size];
|
||||
_array[_size] = default!;
|
||||
_version++;
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the top of the stack.
|
||||
/// </summary>
|
||||
public void Push(T item)
|
||||
{
|
||||
if (_size == _array.Length) {
|
||||
EnsureCapacity(_size + 1);
|
||||
}
|
||||
|
||||
_array[_size++] = item;
|
||||
_version++;
|
||||
}
|
||||
|
||||
private void EnsureCapacity(int min)
|
||||
{
|
||||
int newCapacity = _array.Length == 0 ? DefaultCapacity : _array.Length * 2;
|
||||
if (newCapacity < min) {
|
||||
newCapacity = min;
|
||||
}
|
||||
|
||||
Array.Resize(ref _array, newCapacity);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,162 +1,162 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="StringHashMultiplexer"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class StringHashMultiplexer : IHashMultiplexer<string>
|
||||
{
|
||||
|
||||
private int _initCount, _remainedCount, _hashCache, _hashLast;
|
||||
private string _source, _sourceLast;
|
||||
|
||||
public int RemainedMultiplexCount
|
||||
{
|
||||
get => _remainedCount;
|
||||
set => _initCount = value;
|
||||
}
|
||||
|
||||
public void CacheHash(string obj, int count)
|
||||
{
|
||||
_hashCache = ForceComputeHash(obj);
|
||||
_initCount = count;
|
||||
_remainedCount = _initCount;
|
||||
_source = obj;
|
||||
}
|
||||
|
||||
public bool Equals(string x, string y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public void ExtendCache(int count)
|
||||
{
|
||||
_initCount += count;
|
||||
_remainedCount += count;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe int ForceComputeHash([NotNull] string obj)
|
||||
{
|
||||
int hash;
|
||||
fixed (char* cPtr = obj.AsSpan()) {
|
||||
hash = NativeIntrinsic.Context.city_hash_simplify(cPtr, obj.Length);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public int GetHashCode(string obj)
|
||||
{
|
||||
if (_remainedCount > 0 && ReferenceEquals(_source, obj))
|
||||
{
|
||||
_remainedCount--;
|
||||
return _hashCache;
|
||||
}
|
||||
if (ReferenceEquals(_sourceLast, obj)) {
|
||||
return _hashLast;
|
||||
}
|
||||
_sourceLast = obj;
|
||||
_hashLast = ForceComputeHash(obj);
|
||||
return _hashLast;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class ConcurrentStringHashMultiplexer : IHashMultiplexer<string>, IDisposable
|
||||
{
|
||||
|
||||
private bool disposedValue;
|
||||
private readonly ThreadLocal<StringHashMultiplexer> _multiplexers =
|
||||
new(() => new StringHashMultiplexer());
|
||||
|
||||
public int RemainedMultiplexCount
|
||||
{
|
||||
get => _multiplexers.Value!.RemainedMultiplexCount;
|
||||
set => _multiplexers.Value!.RemainedMultiplexCount = value;
|
||||
}
|
||||
|
||||
public void CacheHash(string obj, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// ~ConcurrentStringHashMultiplexer()
|
||||
// {
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing:true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool Equals(string x, string y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public void ExtendCache(int count)
|
||||
{
|
||||
_multiplexers.Value!.ExtendCache(count);
|
||||
}
|
||||
|
||||
public unsafe int ForceComputeHash([NotNull] string obj)
|
||||
{
|
||||
int hash;
|
||||
fixed (char* cPtr = obj.AsSpan()) {
|
||||
hash = NativeIntrinsic.Context.city_hash_simplify(cPtr, obj.Length);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public int GetHashCode(string obj)
|
||||
{
|
||||
return _multiplexers.Value!.GetHashCode(obj);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing) {
|
||||
_multiplexers.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="StringHashMultiplexer"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace StgSharp.Collections
|
||||
{
|
||||
public sealed class StringHashMultiplexer : IHashMultiplexer<string>
|
||||
{
|
||||
|
||||
private int _initCount, _remainedCount, _hashCache, _hashLast;
|
||||
private string _source, _sourceLast;
|
||||
|
||||
public int RemainedMultiplexCount
|
||||
{
|
||||
get => _remainedCount;
|
||||
set => _initCount = value;
|
||||
}
|
||||
|
||||
public void CacheHash(string obj, int count)
|
||||
{
|
||||
_hashCache = ForceComputeHash(obj);
|
||||
_initCount = count;
|
||||
_remainedCount = _initCount;
|
||||
_source = obj;
|
||||
}
|
||||
|
||||
public bool Equals(string x, string y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public void ExtendCache(int count)
|
||||
{
|
||||
_initCount += count;
|
||||
_remainedCount += count;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe int ForceComputeHash([NotNull] string obj)
|
||||
{
|
||||
int hash;
|
||||
fixed (char* cPtr = obj.AsSpan()) {
|
||||
hash = NativeIntrinsic.Context.city_hash_simplify(cPtr, obj.Length);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public int GetHashCode(string obj)
|
||||
{
|
||||
if (_remainedCount > 0 && ReferenceEquals(_source, obj))
|
||||
{
|
||||
_remainedCount--;
|
||||
return _hashCache;
|
||||
}
|
||||
if (ReferenceEquals(_sourceLast, obj)) {
|
||||
return _hashLast;
|
||||
}
|
||||
_sourceLast = obj;
|
||||
_hashLast = ForceComputeHash(obj);
|
||||
return _hashLast;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class ConcurrentStringHashMultiplexer : IHashMultiplexer<string>, IDisposable
|
||||
{
|
||||
|
||||
private bool disposedValue;
|
||||
private readonly ThreadLocal<StringHashMultiplexer> _multiplexers =
|
||||
new(() => new StringHashMultiplexer());
|
||||
|
||||
public int RemainedMultiplexCount
|
||||
{
|
||||
get => _multiplexers.Value!.RemainedMultiplexCount;
|
||||
set => _multiplexers.Value!.RemainedMultiplexCount = value;
|
||||
}
|
||||
|
||||
public void CacheHash(string obj, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// ~ConcurrentStringHashMultiplexer()
|
||||
// {
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing:true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool Equals(string x, string y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public void ExtendCache(int count)
|
||||
{
|
||||
_multiplexers.Value!.ExtendCache(count);
|
||||
}
|
||||
|
||||
public unsafe int ForceComputeHash([NotNull] string obj)
|
||||
{
|
||||
int hash;
|
||||
fixed (char* cPtr = obj.AsSpan()) {
|
||||
hash = NativeIntrinsic.Context.city_hash_simplify(cPtr, obj.Length);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public int GetHashCode(string obj)
|
||||
{
|
||||
return _multiplexers.Value!.GetHashCode(obj);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing) {
|
||||
_multiplexers.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user