mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-20 17:08:00 +02:00
Moving corlib files out of "System" directory into root
This commit is contained in:
parent
4cd58262e4
commit
7dbfd15292
179 changed files with 3 additions and 0 deletions
118
BeefLibs/corlib/src/Collections/Generic/BinaryHeap.bf
Normal file
118
BeefLibs/corlib/src/Collections/Generic/BinaryHeap.bf
Normal file
|
@ -0,0 +1,118 @@
|
|||
// This file contains portions of code released by Microsoft under the MIT license as part
|
||||
// of an open-sourcing initiative in 2014 of the C# core libraries.
|
||||
// The original source was submitted to https://github.com/Microsoft/referencesource
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
public class BinaryHeap<T>
|
||||
{
|
||||
protected T[] mData ~ delete _;
|
||||
protected int32 mSize = 0;
|
||||
protected Comparison<T> mComparison ~ delete _;
|
||||
|
||||
public this(Comparison<T> comparison)
|
||||
{
|
||||
Constructor(4, comparison);
|
||||
}
|
||||
|
||||
public this(int32 capacity, Comparison<T> comparison)
|
||||
{
|
||||
Constructor(capacity, comparison);
|
||||
}
|
||||
|
||||
private void Constructor(int32 capacity, Comparison<T> comparison)
|
||||
{
|
||||
mData = new T[capacity];
|
||||
mComparison = comparison;
|
||||
}
|
||||
|
||||
public int32 Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an item to the heap
|
||||
public void Add(T item)
|
||||
{
|
||||
if (mSize == mData.Count)
|
||||
Resize();
|
||||
mData[mSize] = item;
|
||||
HeapifyUp(mSize);
|
||||
mSize++;
|
||||
}
|
||||
|
||||
/// Get the item of the root
|
||||
public T Peek()
|
||||
{
|
||||
return mData[0];
|
||||
}
|
||||
|
||||
/// Extract the item of the root
|
||||
public T Pop()
|
||||
{
|
||||
T item = mData[0];
|
||||
mSize--;
|
||||
mData[0] = mData[mSize];
|
||||
HeapifyDown(0);
|
||||
return item;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
private void Resize()
|
||||
{
|
||||
T[] resizedData = new T[mData.Count * 2];
|
||||
Array.Copy(mData, 0, resizedData, 0, mData.Count);
|
||||
delete mData;
|
||||
mData = resizedData;
|
||||
}
|
||||
|
||||
[Optimize]
|
||||
private void HeapifyUp(int32 childIdx)
|
||||
{
|
||||
if (childIdx > 0)
|
||||
{
|
||||
int32 parentIdx = (childIdx - 1) / 2;
|
||||
if (mComparison(mData[childIdx], mData[parentIdx]) > 0)
|
||||
{
|
||||
// swap parent and child
|
||||
T t = mData[parentIdx];
|
||||
mData[parentIdx] = mData[childIdx];
|
||||
mData[childIdx] = t;
|
||||
HeapifyUp(parentIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Optimize]
|
||||
private void HeapifyDown(int32 parentIdx)
|
||||
{
|
||||
int32 leftChildIdx = 2 * parentIdx + 1;
|
||||
int32 rightChildIdx = leftChildIdx + 1;
|
||||
int32 largestChildIdx = parentIdx;
|
||||
if (leftChildIdx < mSize && mComparison(mData[leftChildIdx], mData[largestChildIdx]) > 0)
|
||||
{
|
||||
largestChildIdx = leftChildIdx;
|
||||
}
|
||||
if (rightChildIdx < mSize && mComparison(mData[rightChildIdx], mData[largestChildIdx]) > 0)
|
||||
{
|
||||
largestChildIdx = rightChildIdx;
|
||||
}
|
||||
if (largestChildIdx != parentIdx)
|
||||
{
|
||||
T t = mData[parentIdx];
|
||||
mData[parentIdx] = mData[largestChildIdx];
|
||||
mData[largestChildIdx] = t;
|
||||
HeapifyDown(largestChildIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
996
BeefLibs/corlib/src/Collections/Generic/Dictionary.bf
Normal file
996
BeefLibs/corlib/src/Collections/Generic/Dictionary.bf
Normal file
|
@ -0,0 +1,996 @@
|
|||
// This file contains portions of code released by Microsoft under the MIT license as part
|
||||
// of an open-sourcing initiative in 2014 of the C# core libraries.
|
||||
// The original source was submitted to https://github.com/Microsoft/referencesource
|
||||
|
||||
#if PARANOID
|
||||
#define VERSION_DICTIONARY
|
||||
#endif
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
public class Dictionary<TKey, TValue> where TKey : IHashable //: IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback
|
||||
{
|
||||
private struct Entry
|
||||
{
|
||||
public TKey mKey; // Key of entry
|
||||
public TValue mValue; // Value of entry
|
||||
public int32 mHashCode; // Lower 31 bits of hash code, -1 if unused
|
||||
public int_cosize mNext; // Index of next entry, -1 if last
|
||||
}
|
||||
|
||||
private int_cosize[] mBuckets ~ delete _;
|
||||
private Entry[] mEntries ~ delete _;
|
||||
private int_cosize mCount;
|
||||
private int_cosize mFreeList;
|
||||
private int_cosize mFreeCount;
|
||||
#if VERSION_DICTIONARY
|
||||
private int32 mVersion;
|
||||
const String cVersionError = "Dictionary changed during enumeration";
|
||||
#endif
|
||||
|
||||
public this(): this(0) { }
|
||||
|
||||
public this(int_cosize capacity)
|
||||
{
|
||||
//if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
|
||||
if (capacity > 0) Initialize(capacity);
|
||||
//TODO: this.comparer = comparer ?? EqualityComparer<TKey>.Default;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return mCount - mFreeCount; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return mCount - mFreeCount == 0; }
|
||||
}
|
||||
|
||||
/*public KeyCollection Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
//Contract.Ensures(Contract.Result<KeyCollection>() != null);
|
||||
if (keys == null) keys = new KeyCollection(this);
|
||||
return keys;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*ICollection<TKey> IDictionary<TKey, TValue>.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (keys == null) keys = new KeyCollection(this);
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (keys == null) keys = new KeyCollection(this);
|
||||
return keys;
|
||||
}
|
||||
}*/
|
||||
|
||||
public ValueEnumerator Values
|
||||
{
|
||||
get
|
||||
{
|
||||
//Contract.Ensures(Contract.Result<ValueCollection>() != null);
|
||||
return ValueEnumerator(this);
|
||||
}
|
||||
}
|
||||
|
||||
public KeyEnumerator Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
//Contract.Ensures(Contract.Result<ValueCollection>() != null);
|
||||
return KeyEnumerator(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*ICollection<TValue> IDictionary<TKey, TValue>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (values == null) values = new ValueCollection(this);
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (values == null) values = new ValueCollection(this);
|
||||
return values;
|
||||
}
|
||||
}*/
|
||||
|
||||
public ref TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntry(key);
|
||||
if (i >= 0) return ref mEntries[i].mValue;
|
||||
Runtime.FatalError("Key not found");
|
||||
}
|
||||
set
|
||||
{
|
||||
Insert(key, value, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
Insert(key, value, true);
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
TKey* keyPtr;
|
||||
TValue* valuePtr;
|
||||
bool inserted = Insert(key, false, out keyPtr, out valuePtr);
|
||||
if (!inserted)
|
||||
return false;
|
||||
*keyPtr = key;
|
||||
*valuePtr = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey key, out TKey* keyPtr, out TValue* valuePtr)
|
||||
{
|
||||
return Insert(key, false, out keyPtr, out valuePtr);
|
||||
}
|
||||
|
||||
public enum AddResult
|
||||
{
|
||||
case Added(TKey* keyPtr, TValue* valuePtr);
|
||||
case Exists(TKey* keyPtr, TValue* valuePtr);
|
||||
}
|
||||
|
||||
public AddResult TryAdd(TKey key)
|
||||
{
|
||||
TKey* keyPtr;
|
||||
TValue* valuePtr;
|
||||
if (Insert(key, false, out keyPtr, out valuePtr))
|
||||
return .Added(keyPtr, valuePtr);
|
||||
return .Exists(keyPtr, valuePtr);
|
||||
}
|
||||
|
||||
/*void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair)
|
||||
{
|
||||
Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair)
|
||||
{
|
||||
int i = FindEntry(keyValuePair.Key);
|
||||
if (i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair)
|
||||
{
|
||||
int i = FindEntry(keyValuePair.Key);
|
||||
if (i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value))
|
||||
{
|
||||
Remove(keyValuePair.Key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}*/
|
||||
|
||||
public Result<TValue> GetValue(TKey key)
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntry(key);
|
||||
if (i >= 0) return mEntries[i].mValue;
|
||||
return .Err;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (mCount > 0)
|
||||
{
|
||||
for (int_cosize i = 0; i < mBuckets.Count; i++) mBuckets[i] = -1;
|
||||
//for (int_cosize i = 0; i < mCount; i++)
|
||||
//mEntries[i] = default(Entry);
|
||||
//Array.Clear(entries, 0, count);
|
||||
mFreeList = -1;
|
||||
mCount = 0;
|
||||
mFreeCount = 0;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return FindEntry(key) >= 0;
|
||||
}
|
||||
|
||||
public bool ContainsValue(TValue value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
for (int_cosize i = 0; i < mCount; i++)
|
||||
{
|
||||
if (mEntries[i].mHashCode >= 0 && mEntries[i].mValue == null) return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: IMPORTANT!
|
||||
/*EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].hashCode >= 0 && c.Equals(entries[i].value, value)) return true;
|
||||
}*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this, Enumerator.KeyValuePair);
|
||||
}
|
||||
|
||||
private int FindEntry(TKey key)
|
||||
{
|
||||
if (mBuckets != null)
|
||||
{
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
for (int_cosize i = mBuckets[hashCode % mBuckets.Count]; i >= 0; i = mEntries[i].mNext)
|
||||
{
|
||||
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int FindEntryWith<TAltKey>(TAltKey key) where TAltKey : IOpEquals<TKey>, IHashable
|
||||
{
|
||||
if (mBuckets != null)
|
||||
{
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
for (int_cosize i = mBuckets[hashCode % mBuckets.Count]; i >= 0; i = mEntries[i].mNext)
|
||||
{
|
||||
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void Initialize(int capacity)
|
||||
{
|
||||
int_cosize size = GetPrimeish((int_cosize)capacity);
|
||||
mBuckets = new int_cosize[size];
|
||||
for (int_cosize i < (int_cosize)mBuckets.Count) mBuckets[i] = -1;
|
||||
mEntries = new Entry[size];
|
||||
mFreeList = -1;
|
||||
}
|
||||
|
||||
private void Insert(TKey key, TValue value, bool add)
|
||||
{
|
||||
if (mBuckets == null) Initialize(0);
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
int_cosize targetBucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
|
||||
for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
|
||||
{
|
||||
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
Runtime.FatalError("Adding duplicate");
|
||||
}
|
||||
mEntries[i].mValue = value;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
int_cosize index;
|
||||
if (mFreeCount > 0)
|
||||
{
|
||||
index = mFreeList;
|
||||
mFreeList = mEntries[index].mNext;
|
||||
mFreeCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCount == mEntries.Count)
|
||||
{
|
||||
Resize();
|
||||
targetBucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
}
|
||||
index = mCount;
|
||||
mCount++;
|
||||
}
|
||||
|
||||
mEntries[index].mHashCode = hashCode;
|
||||
mEntries[index].mNext = mBuckets[targetBucket];
|
||||
mEntries[index].mKey = key;
|
||||
mEntries[index].mValue = value;
|
||||
mBuckets[targetBucket] = index;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool Insert(TKey key, bool add, out TKey* keyPtr, out TValue* valuePtr)
|
||||
{
|
||||
if (mBuckets == null) Initialize(0);
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
int_cosize targetBucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
|
||||
for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
|
||||
{
|
||||
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
Runtime.FatalError("Adding duplicate entry");
|
||||
}
|
||||
keyPtr = &mEntries[i].mKey;
|
||||
valuePtr = &mEntries[i].mValue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int_cosize index;
|
||||
if (mFreeCount > 0)
|
||||
{
|
||||
index = mFreeList;
|
||||
mFreeList = mEntries[index].mNext;
|
||||
mFreeCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCount == mEntries.Count)
|
||||
{
|
||||
Resize();
|
||||
targetBucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
}
|
||||
index = mCount;
|
||||
mCount++;
|
||||
}
|
||||
|
||||
mEntries[index].mHashCode = hashCode;
|
||||
mEntries[index].mNext = mBuckets[targetBucket];
|
||||
mEntries[index].mKey = key;
|
||||
mBuckets[targetBucket] = index;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
|
||||
keyPtr = &mEntries[index].mKey;
|
||||
valuePtr = &mEntries[index].mValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Close to prime but faster to compute
|
||||
int_cosize GetPrimeish(int_cosize min)
|
||||
{
|
||||
// This is a minimal effort to help address-aligned data
|
||||
return (min | 1);
|
||||
}
|
||||
|
||||
int_cosize ExpandSize(int_cosize oldSize)
|
||||
{
|
||||
int_cosize newSize = 2 * oldSize;
|
||||
return GetPrimeish(newSize);
|
||||
}
|
||||
|
||||
private void Resize()
|
||||
{
|
||||
Resize(ExpandSize(mCount), false);
|
||||
}
|
||||
|
||||
private void Resize(int newSize, bool forceNewHashCodes)
|
||||
{
|
||||
Contract.Assert(newSize >= mEntries.Count);
|
||||
int_cosize[] newBuckets = new int_cosize[newSize];
|
||||
for (int_cosize i = 0; i < newBuckets.Count; i++) newBuckets[i] = -1;
|
||||
Entry[] newEntries = new Entry[newSize];
|
||||
mEntries.CopyTo(newEntries, 0, 0, mCount);
|
||||
if (forceNewHashCodes)
|
||||
{
|
||||
for (int_cosize i = 0; i < mCount; i++)
|
||||
{
|
||||
if (newEntries[i].mHashCode != -1)
|
||||
{
|
||||
newEntries[i].mHashCode = (int_cosize)newEntries[i].mKey.GetHashCode() & 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int_cosize i = 0; i < mCount; i++)
|
||||
{
|
||||
if (newEntries[i].mHashCode >= 0)
|
||||
{
|
||||
int_cosize bucket = (int_cosize)(newEntries[i].mHashCode % newSize);
|
||||
newEntries[i].mNext = newBuckets[bucket];
|
||||
newBuckets[bucket] = i;
|
||||
}
|
||||
}
|
||||
|
||||
delete mBuckets;
|
||||
delete mEntries;
|
||||
|
||||
mBuckets = newBuckets;
|
||||
mEntries = newEntries;
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
ThrowUnimplemented();
|
||||
//ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
|
||||
}
|
||||
|
||||
if (mBuckets != null)
|
||||
{
|
||||
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
int_cosize bucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
int_cosize last = -1;
|
||||
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
|
||||
{
|
||||
if ((mEntries[i].mHashCode == hashCode) && (mEntries[i].mKey == key))
|
||||
{
|
||||
if (last < 0)
|
||||
{
|
||||
mBuckets[bucket] = mEntries[i].mNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEntries[last].mNext = mEntries[i].mNext;
|
||||
}
|
||||
mEntries[i].mHashCode = -1;
|
||||
mEntries[i].mNext = mFreeList;
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
mEntries[i].mKey = default;
|
||||
mEntries[i].mValue = default;
|
||||
#endif
|
||||
mFreeList = i;
|
||||
mFreeCount++;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Result<(TKey key, TValue value)> GetAndRemove(TKey key)
|
||||
{
|
||||
if (mBuckets != null)
|
||||
{
|
||||
|
||||
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF;
|
||||
int_cosize bucket = hashCode % (int_cosize)mBuckets.Count;
|
||||
int_cosize last = -1;
|
||||
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
|
||||
{
|
||||
if ((mEntries[i].mHashCode == hashCode) && (mEntries[i].mKey == key))
|
||||
{
|
||||
if (last < 0)
|
||||
{
|
||||
mBuckets[bucket] = mEntries[i].mNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEntries[last].mNext = mEntries[i].mNext;
|
||||
}
|
||||
TKey entryKey = mEntries[i].mKey;
|
||||
TValue result = mEntries[i].mValue;
|
||||
|
||||
mEntries[i].mHashCode = -1;
|
||||
mEntries[i].mNext = mFreeList;
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
mEntries[i].mKey = default(TKey);
|
||||
mEntries[i].mValue = default(TValue);
|
||||
#endif
|
||||
mFreeList = i;
|
||||
mFreeCount++;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion++;
|
||||
#endif
|
||||
return .Ok((entryKey, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
return .Err;
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntry(key);
|
||||
if (i >= 0)
|
||||
{
|
||||
value = mEntries[i].mValue;
|
||||
return true;
|
||||
}
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TKey matchKey, out TValue value)
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntry(key);
|
||||
if (i >= 0)
|
||||
{
|
||||
matchKey = mEntries[i].mKey;
|
||||
value = mEntries[i].mValue;
|
||||
return true;
|
||||
}
|
||||
matchKey = default(TKey);
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetWith<TAltKey>(TAltKey key, out TKey matchKey, out TValue value) where TAltKey : IOpEquals<TKey>, IHashable
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntryWith(key);
|
||||
if (i >= 0)
|
||||
{
|
||||
matchKey = mEntries[i].mKey;
|
||||
value = mEntries[i].mValue;
|
||||
return true;
|
||||
}
|
||||
matchKey = default(TKey);
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TValue GetValueOrDefault(TKey key)
|
||||
{
|
||||
int_cosize i = (int_cosize)FindEntry(key);
|
||||
if (i >= 0)
|
||||
{
|
||||
return mEntries[i].mValue;
|
||||
}
|
||||
return default(TValue);
|
||||
}
|
||||
|
||||
private static bool IsCompatibleKey(Object key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
ThrowUnimplemented();
|
||||
//ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
|
||||
}
|
||||
return (key is TKey);
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<(TKey key, TValue value)>//, IDictionaryEnumerator
|
||||
{
|
||||
private Dictionary<TKey, TValue> mDictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
private int_cosize mVersion;
|
||||
#endif
|
||||
private int_cosize mIndex;
|
||||
private int_cosize mCurrentIndex;
|
||||
//private KeyValuePair<TKey, TValue> current;
|
||||
private int_cosize mGetEnumeratorRetType; // What should Enumerator.Current return?
|
||||
|
||||
internal const int_cosize DictEntry = 1;
|
||||
internal const int_cosize KeyValuePair = 2;
|
||||
|
||||
internal this(Dictionary<TKey, TValue> dictionary, int_cosize getEnumeratorRetType)
|
||||
{
|
||||
mDictionary = dictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion = dictionary.mVersion;
|
||||
#endif
|
||||
mIndex = 0;
|
||||
mGetEnumeratorRetType = getEnumeratorRetType;
|
||||
//current = KeyValuePair<TKey, TValue>();
|
||||
//current = default(KeyValuePair<TKey, TValue>);
|
||||
mCurrentIndex = -1;
|
||||
}
|
||||
|
||||
#if VERSION_DICTIONARY
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mDictionary.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
while ((uint)mIndex < (uint)mDictionary.mCount)
|
||||
{
|
||||
if (mDictionary.mEntries[mIndex].mHashCode >= 0)
|
||||
{
|
||||
mCurrentIndex = mIndex;
|
||||
//current = KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
mIndex = mDictionary.mCount + 1;
|
||||
//current = default(KeyValuePair<TKey, TValue>);
|
||||
mCurrentIndex = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public ref TKey Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref mDictionary.mEntries[mCurrentIndex].mKey;
|
||||
}
|
||||
}
|
||||
|
||||
public ref TValue Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref mDictionary.mEntries[mCurrentIndex].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public (TKey key, TValue value) Current
|
||||
{
|
||||
get { return (mDictionary.mEntries[mCurrentIndex].mKey, mDictionary.mEntries[mCurrentIndex].mValue); }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetValue(TValue value)
|
||||
{
|
||||
mDictionary.mEntries[mCurrentIndex].mValue = value;
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
mIndex = 0;
|
||||
//current = default(KeyValuePair<TKey, TValue>);
|
||||
mCurrentIndex = -1;
|
||||
}
|
||||
|
||||
/*DictionaryEntry IDictionaryEnumerator.Entry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary.count + 1))
|
||||
{
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
|
||||
}
|
||||
|
||||
return new DictionaryEntry(current.Key, current.Value);
|
||||
}
|
||||
}
|
||||
|
||||
object IDictionaryEnumerator.Key
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary.count + 1))
|
||||
{
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
|
||||
}
|
||||
|
||||
return current.Key;
|
||||
}
|
||||
}
|
||||
|
||||
object IDictionaryEnumerator.Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary.count + 1))
|
||||
{
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
|
||||
}
|
||||
|
||||
return current.Value;
|
||||
}
|
||||
}*/
|
||||
|
||||
public Result<(TKey key, TValue value)> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ValueEnumerator : IEnumerator<TValue>, IResettable
|
||||
{
|
||||
private Dictionary<TKey, TValue> mDictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
private int_cosize mVersion;
|
||||
#endif
|
||||
private int_cosize mIndex;
|
||||
private TValue mCurrent;
|
||||
|
||||
internal const int_cosize cDictEntry = 1;
|
||||
internal const int_cosize cKeyValuePair = 2;
|
||||
|
||||
internal this(Dictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
mDictionary = dictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion = dictionary.mVersion;
|
||||
#endif
|
||||
mIndex = 0;
|
||||
mCurrent = default;
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
while ((uint)mIndex < (uint)mDictionary.mCount)
|
||||
{
|
||||
if (mDictionary.mEntries[mIndex].mHashCode >= 0)
|
||||
{
|
||||
mCurrent = mDictionary.mEntries[mIndex].mValue;
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
mIndex = mDictionary.mCount + 1;
|
||||
mCurrent = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TValue Current
|
||||
{
|
||||
get { return mCurrent; }
|
||||
}
|
||||
|
||||
public ref TKey Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref mDictionary.mEntries[mIndex].mKey;
|
||||
}
|
||||
}
|
||||
|
||||
#if VERSION_DICTIONARY
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mDictionary.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
mIndex = 0;
|
||||
mCurrent = default;
|
||||
}
|
||||
|
||||
public Result<TValue> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public struct RefValueEnumerator : IEnumerator<TValue>, IResettable
|
||||
{
|
||||
private Dictionary<TKey, TValue> mDictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
private int_cosize mVersion;
|
||||
#endif
|
||||
private int_cosize mIndex;
|
||||
private TValue* mCurrent;
|
||||
|
||||
internal const int_cosize DictEntry = 1;
|
||||
internal const int_cosize KeyValuePair = 2;
|
||||
|
||||
internal this(Dictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
mDictionary = dictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion = dictionary.mVersion;
|
||||
#endif
|
||||
mIndex = 0;
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
#if VERSION_DICTIONARY
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mDictionary.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
while ((uint32)mIndex < (uint32)mDictionary.mCount)
|
||||
{
|
||||
if (mDictionary.mEntries[mIndex].mHashCode >= 0)
|
||||
{
|
||||
mCurrent = &mDictionary.mEntries[mIndex].mValue;
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
mIndex = mDictionary.mCount + 1;
|
||||
mCurrent = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TValue Current
|
||||
{
|
||||
get { return *mCurrent; }
|
||||
}
|
||||
|
||||
public ref TKey Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref mDictionary.mEntries[mIndex - 1].mKey;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
mIndex = 0;
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
public Result<TValue> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public struct KeyEnumerator : IEnumerator<TKey>, IResettable
|
||||
{
|
||||
private Dictionary<TKey, TValue> mDictionary;
|
||||
# if VERSION_DICTIONARY
|
||||
private int32 mVersion;
|
||||
#endif
|
||||
private int_cosize mIndex;
|
||||
private TKey* mCurrent;
|
||||
|
||||
internal const int_cosize DictEntry = 1;
|
||||
internal const int_cosize KeyValuePair = 2;
|
||||
|
||||
internal this(Dictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
mDictionary = dictionary;
|
||||
#if VERSION_DICTIONARY
|
||||
mVersion = dictionary.mVersion;
|
||||
#endif
|
||||
mIndex = 0;
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
#if VERSION_DICTIONARY
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mDictionary.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
|
||||
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
while ((uint32)mIndex < (uint32)mDictionary.mCount)
|
||||
{
|
||||
if (mDictionary.mEntries[mIndex].mHashCode >= 0)
|
||||
{
|
||||
mCurrent = &mDictionary.mEntries[mIndex].mKey;
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
mIndex = mDictionary.mCount + 1;
|
||||
mCurrent = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TKey Current
|
||||
{
|
||||
get { return *mCurrent; }
|
||||
}
|
||||
|
||||
public ref TValue Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref mDictionary.mEntries[mIndex - 1].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
#if VERSION_DICTIONARY
|
||||
CheckVersion();
|
||||
#endif
|
||||
mIndex = 0;
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
public Result<TKey> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1140
BeefLibs/corlib/src/Collections/Generic/HashSet.bf
Normal file
1140
BeefLibs/corlib/src/Collections/Generic/HashSet.bf
Normal file
File diff suppressed because it is too large
Load diff
4
BeefLibs/corlib/src/Collections/Generic/IComparer.bf
Normal file
4
BeefLibs/corlib/src/Collections/Generic/IComparer.bf
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace System.Collections.Generic
|
||||
{
|
||||
|
||||
}
|
11
BeefLibs/corlib/src/Collections/Generic/IEqualityComparer.bf
Normal file
11
BeefLibs/corlib/src/Collections/Generic/IEqualityComparer.bf
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace System.Collections.Generic
|
||||
{
|
||||
using System;
|
||||
|
||||
public interface IEqualityComparer</*in*/ T>
|
||||
{
|
||||
bool Equals(T x, T y);
|
||||
int GetHashCode(T obj);
|
||||
}
|
||||
}
|
||||
|
39
BeefLibs/corlib/src/Collections/Generic/KeyValuePair.bf
Normal file
39
BeefLibs/corlib/src/Collections/Generic/KeyValuePair.bf
Normal file
|
@ -0,0 +1,39 @@
|
|||
namespace System.Collections.Generic
|
||||
{
|
||||
public struct KeyValuePair<TKey, TValue>
|
||||
{
|
||||
private TKey mKey;
|
||||
private TValue mValue;
|
||||
|
||||
public this(TKey key, TValue value)
|
||||
{
|
||||
this.mKey = key;
|
||||
this.mValue = value;
|
||||
}
|
||||
|
||||
public TKey Key
|
||||
{
|
||||
get { return mKey; }
|
||||
}
|
||||
|
||||
public TValue Value
|
||||
{
|
||||
get { return mValue; }
|
||||
}
|
||||
|
||||
public override void ToString(String strOut)
|
||||
{
|
||||
strOut.Append('[');
|
||||
if (Key != null)
|
||||
{
|
||||
Key.ToString(strOut);
|
||||
}
|
||||
strOut.Append(", ");
|
||||
if (Value != null)
|
||||
{
|
||||
Value.ToString(strOut);
|
||||
}
|
||||
strOut.Append(']');
|
||||
}
|
||||
}
|
||||
}
|
778
BeefLibs/corlib/src/Collections/Generic/List.bf
Normal file
778
BeefLibs/corlib/src/Collections/Generic/List.bf
Normal file
|
@ -0,0 +1,778 @@
|
|||
// This file contains portions of code released by Microsoft under the MIT license as part
|
||||
// of an open-sourcing initiative in 2014 of the C# core libraries.
|
||||
// The original source was submitted to https://github.com/Microsoft/referencesource
|
||||
|
||||
#if PARANOID
|
||||
#define VERSION_LIST
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Runtime;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
interface IList
|
||||
{
|
||||
Variant this[int index]
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
|
||||
public class List<T> : IEnumerable<T>, IList
|
||||
{
|
||||
private const int_cosize cDefaultCapacity = 4;
|
||||
|
||||
const int_cosize SizeFlags = 0x7FFFFFFF;
|
||||
const int_cosize DynAllocFlag = (int_cosize)0x80000000;
|
||||
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
static DbgRawAllocData sRawAllocData;
|
||||
public static this()
|
||||
{
|
||||
sRawAllocData.mMarkFunc = null;
|
||||
sRawAllocData.mMaxStackTrace = 1;
|
||||
sRawAllocData.mType = typeof(T);
|
||||
}
|
||||
#endif
|
||||
|
||||
private T* mItems;
|
||||
private int_cosize mSize;
|
||||
private int_cosize mAllocSizeAndFlags;
|
||||
#if VERSION_LIST
|
||||
private int32 mVersion;
|
||||
const String cVersionError = "List changed during enumeration";
|
||||
#endif
|
||||
|
||||
public int AllocSize
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mAllocSizeAndFlags & SizeFlags;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDynAlloc
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return (mAllocSizeAndFlags & DynAllocFlag) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public this()
|
||||
{
|
||||
}
|
||||
|
||||
public this(IEnumerator<T> enumerator)
|
||||
{
|
||||
for (var item in enumerator)
|
||||
Add(item);
|
||||
}
|
||||
|
||||
[AllowAppend]
|
||||
public this(int capacity)
|
||||
{
|
||||
Debug.Assert((uint)capacity <= (uint)SizeFlags);
|
||||
T* items = append T[capacity]* (?);
|
||||
if (capacity > 0)
|
||||
{
|
||||
mItems = items;
|
||||
mAllocSizeAndFlags = (int_cosize)(capacity & SizeFlags);
|
||||
}
|
||||
}
|
||||
/*public this(int capacity)
|
||||
{
|
||||
Debug.Assert((uint)capacity <= (uint)SizeFlags);
|
||||
if (capacity > 0)
|
||||
{
|
||||
mItems = Alloc(capacity);
|
||||
mAllocSizeAndFlags = (int_cosize)(capacity | DynAllocFlag);
|
||||
}
|
||||
}*/
|
||||
|
||||
public ~this()
|
||||
{
|
||||
#if DBG
|
||||
int typeId = typeof(T).GetTypeId();
|
||||
if (typeId == sDebugTypeId)
|
||||
{
|
||||
Debug.WriteLine("Dealloc {0} {1}", scope Object[] { this, mItems } );
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsDynAlloc)
|
||||
{
|
||||
var items = mItems;
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
mItems = null;
|
||||
Interlocked.Fence();
|
||||
#endif
|
||||
Free(items);
|
||||
}
|
||||
}
|
||||
|
||||
public T* Ptr
|
||||
{
|
||||
get
|
||||
{
|
||||
return mItems;
|
||||
}
|
||||
}
|
||||
|
||||
#if DBG
|
||||
static int_cosize sDebugTypeId = 470;
|
||||
static int_cosize sDebugIdx = 0;
|
||||
#endif
|
||||
|
||||
public int Capacity
|
||||
{
|
||||
get
|
||||
{
|
||||
return mAllocSizeAndFlags & SizeFlags;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Debug.Assert((uint)value <= (uint)SizeFlags);
|
||||
if (value != AllocSize)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
T* newItems = Alloc(value);
|
||||
|
||||
#if DBG
|
||||
int typeId = typeof(T).GetTypeId();
|
||||
if (typeId == sDebugTypeId)
|
||||
{
|
||||
Debug.WriteLine("Alloc {0} {1} {2}", scope Object[] { this, newItems, sDebugIdx } );
|
||||
sDebugIdx++;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mSize > 0)
|
||||
Internal.MemCpy(newItems, mItems, mSize * strideof(T), alignof(T));
|
||||
|
||||
var oldItems = mItems;
|
||||
mItems = newItems;
|
||||
if (IsDynAlloc)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
// We need to avoid scanning a deleted mItems
|
||||
Interlocked.Fence();
|
||||
#endif
|
||||
Free(oldItems);
|
||||
}
|
||||
mAllocSizeAndFlags = (.)(value | DynAllocFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
Free(mItems);
|
||||
mItems = null;
|
||||
mAllocSizeAndFlags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
return mSize == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public ref T this[int index]
|
||||
{
|
||||
[Checked]
|
||||
get
|
||||
{
|
||||
Runtime.Assert((uint)index < (uint)mSize);
|
||||
return ref mItems[index];
|
||||
}
|
||||
|
||||
[Unchecked, Inline]
|
||||
get
|
||||
{
|
||||
return ref mItems[index];
|
||||
}
|
||||
|
||||
[Checked]
|
||||
set
|
||||
{
|
||||
Runtime.Assert((uint)index < (uint)mSize);
|
||||
mItems[index] = value;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
[Unchecked, Inline]
|
||||
set
|
||||
{
|
||||
mItems[index] = value;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public ref T Back
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(mSize != 0);
|
||||
return ref mItems[mSize - 1];
|
||||
}
|
||||
}
|
||||
|
||||
Variant IList.this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return [Unbound]Variant.Create(this[index]);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
ThrowUnimplemented();
|
||||
}
|
||||
}
|
||||
|
||||
protected T* Alloc(int size)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
// We don't want to use the default mark function because the GC will mark the entire array,
|
||||
// whereas we have a custom marking routine because we only want to mark up to mSize
|
||||
return (T*)Internal.Dbg_RawAlloc(size * strideof(T), &sRawAllocData);
|
||||
#else
|
||||
return new T[size]*(?);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected void Free(T* val)
|
||||
{
|
||||
delete val;
|
||||
}
|
||||
/*protected T[] Alloc(int size)
|
||||
{
|
||||
return new:this T[size];
|
||||
}
|
||||
|
||||
protected void Free(Object obj)
|
||||
{
|
||||
delete:this obj;
|
||||
}
|
||||
|
||||
protected virtual Object AllocObject(TypeInstance type, int size)
|
||||
{
|
||||
return Internal.ObjectAlloc(type, size);
|
||||
}
|
||||
|
||||
protected virtual void FreeObject(Object obj)
|
||||
{
|
||||
delete obj;
|
||||
}*/
|
||||
|
||||
/// Adds an item to the back of the list.
|
||||
public void Add(T item)
|
||||
{
|
||||
if (mSize == AllocSize) EnsureCapacity(mSize + 1);
|
||||
mItems[mSize++] = item;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Adds an item to the back of the list.
|
||||
public void Add(Span<T> addSpan)
|
||||
{
|
||||
if (mSize == AllocSize) EnsureCapacity(mSize + addSpan.Length);
|
||||
for (var val in ref addSpan)
|
||||
mItems[mSize++] = val;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a pointer to the start of the added uninitialized section
|
||||
public T* GrowUnitialized(int addSize)
|
||||
{
|
||||
if (mSize + addSize > AllocSize) EnsureCapacity(mSize + addSize);
|
||||
mSize += (int_cosize)addSize;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
if (addSize == 0)
|
||||
return null;
|
||||
return &mItems[mSize - addSize];
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (mSize > 0)
|
||||
{
|
||||
mSize = 0;
|
||||
}
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*public static void DeleteItemsAndClear<T>(List<T> list) where T : delete
|
||||
{
|
||||
foreach (var item in list)
|
||||
delete item;
|
||||
list.Clear();
|
||||
}*/
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (mItems[i] == null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (mItems[i] == item)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array)
|
||||
{
|
||||
CopyTo(array, 0);
|
||||
}
|
||||
|
||||
public void CopyTo(List<T> destList)
|
||||
{
|
||||
destList.EnsureCapacity(mSize);
|
||||
destList.mSize = mSize;
|
||||
if (mSize > 0)
|
||||
Internal.MemCpy(destList.mItems, mItems, mSize * strideof(T), alignof(T));
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
// Delegate rest of error checking to Array.Copy.
|
||||
for (int i = 0; i < mSize; i++)
|
||||
array[i + arrayIndex] = mItems[i];
|
||||
}
|
||||
|
||||
public void CopyTo(int index, T[] array, int arrayIndex, int count)
|
||||
{
|
||||
// Delegate rest of error checking to Array.Copy.
|
||||
for (int i = 0; i < count; i++)
|
||||
array[i + arrayIndex] = mItems[i + index];
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int min)
|
||||
{
|
||||
int allocSize = AllocSize;
|
||||
if (allocSize < min)
|
||||
{
|
||||
int_cosize newCapacity = (int_cosize)(allocSize == 0 ? cDefaultCapacity : allocSize * 2);
|
||||
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
|
||||
// Note that this check works even when mItems.Length overflowed thanks to the (uint) cast
|
||||
//if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
|
||||
if (newCapacity < min) newCapacity = (int_cosize)min;
|
||||
Capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reserve(int size)
|
||||
{
|
||||
EnsureCapacity(size);
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this);
|
||||
}
|
||||
|
||||
public int_cosize FindIndex(Predicate<T> match)
|
||||
{
|
||||
for (int_cosize i = 0; i < mSize; i++)
|
||||
if (match(mItems[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int_cosize IndexOf(T item)
|
||||
{
|
||||
//return Array.IndexOf(mItems, item, 0, mSize);
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (mItems[i] == item)
|
||||
return (int_cosize)i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int_cosize IndexOf(T item, int index)
|
||||
{
|
||||
for (int i = index; i < mSize; i++)
|
||||
if (mItems[i] == item)
|
||||
return (int_cosize)i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int_cosize IndexOf(T item, int index, int count)
|
||||
{
|
||||
for (int i = index; i < index + count; i++)
|
||||
if (mItems[i] == item)
|
||||
return (int_cosize)i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (mSize == AllocSize) EnsureCapacity(mSize + 1);
|
||||
if (index < mSize)
|
||||
{
|
||||
Internal.MemCpy(mItems + index + 1, mItems + index, (mSize - index) * strideof(T), alignof(T));
|
||||
}
|
||||
mItems[index] = item;
|
||||
mSize++;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Debug.Assert((uint)index < (uint)mSize);
|
||||
if (index < mSize - 1)
|
||||
{
|
||||
Internal.MemCpy(mItems + index, mItems + index + 1, (mSize - index - 1) * strideof(T), alignof(T));
|
||||
}
|
||||
mSize--;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RemoveRange(int index, int count)
|
||||
{
|
||||
Debug.Assert((uint)index + (uint)count <= (uint)mSize);
|
||||
if (index + count < mSize - 1)
|
||||
{
|
||||
for (int i = index; i < mSize - count; i++)
|
||||
mItems[i] = mItems[i + count];
|
||||
}
|
||||
mSize -= (.)count;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RemoveAtFast(int index)
|
||||
{
|
||||
Debug.Assert((uint32)index < (uint32)mSize);
|
||||
mSize--;
|
||||
if (mSize > 0)
|
||||
mItems[index] = mItems[mSize];
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Sort(Comparison<T> comp)
|
||||
{
|
||||
var sorter = Sorter<T, void>(mItems, null, mSize, comp);
|
||||
sorter.Sort(0, mSize);
|
||||
}
|
||||
|
||||
public int RemoveAll(Predicate<T> match)
|
||||
{
|
||||
int_cosize freeIndex = 0; // the first free slot in items array
|
||||
|
||||
// Find the first item which needs to be removed.
|
||||
while (freeIndex < mSize && !match(mItems[freeIndex])) freeIndex++;
|
||||
if (freeIndex >= mSize) return 0;
|
||||
|
||||
int_cosize current = freeIndex + 1;
|
||||
while (current < mSize)
|
||||
{
|
||||
// Find the first item which needs to be kept.
|
||||
while (current < mSize && match(mItems[current])) current++;
|
||||
|
||||
if (current < mSize)
|
||||
{
|
||||
// copy item to the free slot.
|
||||
mItems[freeIndex++] = mItems[current++];
|
||||
}
|
||||
}
|
||||
|
||||
int_cosize result = mSize - freeIndex;
|
||||
mSize = freeIndex;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
public T PopBack()
|
||||
{
|
||||
T backVal = mItems[mSize - 1];
|
||||
mSize--;
|
||||
return backVal;
|
||||
}
|
||||
|
||||
public T PopFront()
|
||||
{
|
||||
T backVal = mItems[0];
|
||||
RemoveAt(0);
|
||||
return backVal;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
int_cosize index = IndexOf(item);
|
||||
if (index >= 0)
|
||||
{
|
||||
RemoveAt(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Searches a section of the list for a given element using a binary search
|
||||
/// algorithm. Elements of the list are compared to the search value using
|
||||
/// the given IComparer interface. If comparer is null, elements of
|
||||
/// the list are compared to the search value using the IComparable
|
||||
/// interface, which in that case must be implemented by all elements of the
|
||||
/// list and the given search value. This method assumes that the given
|
||||
/// section of the list is already sorted; if this is not the case, the
|
||||
/// result will be incorrect.
|
||||
///
|
||||
/// The method returns the index of the given value in the list. If the
|
||||
/// list does not contain the given value, the method returns a negative
|
||||
/// integer. The bitwise complement operator (~) can be applied to a
|
||||
/// negative result to produce the index of the first element (if any) that
|
||||
/// is larger than the given search value. This is also the index at which
|
||||
/// the search value should be inserted into the list in order for the list
|
||||
/// to remain sorted.
|
||||
///
|
||||
/// The method uses the Array.BinarySearch method to perform the
|
||||
/// search.
|
||||
///
|
||||
/// @brief Searches a section of the list for a given element using a binary search algorithm.
|
||||
public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
|
||||
{
|
||||
return (int_cosize)Array.BinarySearch(mItems, index, count, item, comparer);
|
||||
}
|
||||
|
||||
public int_cosize BinarySearch(T item, IComparer<T> comparer)
|
||||
{
|
||||
//Contract.Ensures(Contract.Result<int>() <= Count);
|
||||
return (int_cosize)BinarySearch(0, Count, item, comparer);
|
||||
}
|
||||
|
||||
public static operator Span<T>(List<T> list)
|
||||
{
|
||||
return Span<T>(list.mItems, list.mSize);
|
||||
}
|
||||
|
||||
protected override void GCMarkMembers()
|
||||
{
|
||||
if (mItems == null)
|
||||
return;
|
||||
let type = typeof(T);
|
||||
if ((type.mTypeFlags & .WantsMark) == 0)
|
||||
return;
|
||||
for (int i < mSize)
|
||||
{
|
||||
GC.Mark_Unbound(mItems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public struct Enumerator : IRefEnumerator<T>, IResettable
|
||||
{
|
||||
private List<T> mList;
|
||||
private int mIndex;
|
||||
#if VERSION_LIST
|
||||
private int32 mVersion;
|
||||
#endif
|
||||
private T* mCurrent;
|
||||
|
||||
internal this(List<T> list)
|
||||
{
|
||||
mList = list;
|
||||
mIndex = 0;
|
||||
#if VERSION_LIST
|
||||
mVersion = list.mVersion;
|
||||
#endif
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
#if VERSION_LIST
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mList.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
List<T> localList = mList;
|
||||
if ((uint(mIndex) < uint(localList.mSize)))
|
||||
{
|
||||
mCurrent = &localList.mItems[mIndex];
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
return MoveNextRare();
|
||||
}
|
||||
|
||||
private bool MoveNextRare() mut
|
||||
{
|
||||
#if VERSION_LIST
|
||||
CheckVersion();
|
||||
#endif
|
||||
mIndex = mList.mSize + 1;
|
||||
mCurrent = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return *mCurrent;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
*mCurrent = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ref T CurrentRef
|
||||
{
|
||||
get
|
||||
{
|
||||
return ref *mCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return mIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return mList.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove() mut
|
||||
{
|
||||
int curIdx = mIndex - 1;
|
||||
mList.RemoveAt(curIdx);
|
||||
#if VERSION_LIST
|
||||
mVersion = mList.mVersion;
|
||||
#endif
|
||||
mIndex = curIdx;
|
||||
}
|
||||
|
||||
public void RemoveFast() mut
|
||||
{
|
||||
int curIdx = mIndex - 1;
|
||||
int lastIdx = mList.Count - 1;
|
||||
if (curIdx < lastIdx)
|
||||
mList[curIdx] = mList[lastIdx];
|
||||
mList.RemoveAt(lastIdx);
|
||||
#if VERSION_LIST
|
||||
mVersion = mList.mVersion;
|
||||
#endif
|
||||
mIndex = curIdx;
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
mIndex = 0;
|
||||
mCurrent = null;
|
||||
}
|
||||
|
||||
public Result<T> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
|
||||
public Result<T*> GetNextRef() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return &CurrentRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension List<T> where T : IOpComparable
|
||||
{
|
||||
public int_cosize BinarySearch(T item)
|
||||
{
|
||||
return (int_cosize)BinarySearch(0, Count, item, scope CompareWrapper<T>());
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
Sort(scope (lhs, rhs) => lhs <=> rhs);
|
||||
}
|
||||
}
|
||||
|
||||
class ListWithAlloc<T> : List<T>
|
||||
{
|
||||
IRawAllocator mAlloc;
|
||||
|
||||
public this(IRawAllocator alloc)
|
||||
{
|
||||
mAlloc = alloc;
|
||||
}
|
||||
|
||||
/*protected override void* Alloc(int size, int align)
|
||||
{
|
||||
return mAlloc.Alloc(size, align);
|
||||
}
|
||||
|
||||
protected override void Free(void* ptr)
|
||||
{
|
||||
mAlloc.Free(ptr);
|
||||
}*/
|
||||
}
|
||||
}
|
350
BeefLibs/corlib/src/Collections/Generic/Queue.bf
Normal file
350
BeefLibs/corlib/src/Collections/Generic/Queue.bf
Normal file
|
@ -0,0 +1,350 @@
|
|||
// This file contains portions of code released by Microsoft under the MIT license as part
|
||||
// of an open-sourcing initiative in 2014 of the C# core libraries.
|
||||
// The original source was submitted to https://github.com/Microsoft/referencesource
|
||||
|
||||
#if PARANOID
|
||||
#define VERSION_QUEUE
|
||||
#endif
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// A simple Queue of generic items. Internally it is implemented as a
|
||||
/// circular buffer, so Enqueue can be O(n). Dequeue is O(1).
|
||||
public class Queue<T> : IEnumerable<T> //, System.Collections.ICollection, IReadOnlyCollection<T>
|
||||
{
|
||||
private T[] mArray;
|
||||
private int_cosize mHead; // First valid element in the queue
|
||||
private int_cosize mTail; // Last valid element in the queue
|
||||
private int_cosize mSize; // Number of elements.
|
||||
#if VERSION_QUEUE
|
||||
private int32 mVersion;
|
||||
const String cVersionError = "Queue changed during enumeration";
|
||||
#endif
|
||||
private Object mSyncRoot;
|
||||
|
||||
private const int32 cMinimumGrow = 4;
|
||||
private const int32 cShrinkThreshold = 32;
|
||||
private const int32 cGrowFactor = 200; // double each time
|
||||
private const int32 cDefaultCapacity = 4;
|
||||
static T[] sEmptyArray = new T[0] ~ delete _;
|
||||
|
||||
/// Creates a queue with room for capacity objects. The default initial
|
||||
/// capacity and grow factor are used.
|
||||
public this()
|
||||
{
|
||||
mArray = sEmptyArray;
|
||||
}
|
||||
|
||||
/// Creates a queue with room for capacity objects. The default grow factor
|
||||
/// is used.
|
||||
public this(int capacity)
|
||||
{
|
||||
Debug.Assert(capacity >= 0);
|
||||
mArray = new T[capacity];
|
||||
mHead = 0;
|
||||
mTail = 0;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
// Fills a Queue with the elements of an ICollection. Uses the enumerator
|
||||
// to get each of the elements.
|
||||
//
|
||||
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue3"]/*' />
|
||||
/*public void Set<T>(T collection) where T : IEnumerable<T>
|
||||
{
|
||||
if (collection == null)
|
||||
//ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
|
||||
Runtime.FatalError();
|
||||
|
||||
_array = new T[_DefaultCapacity];
|
||||
_size = 0;
|
||||
_version = 0;
|
||||
|
||||
using (var en = collection.GetEnumerator())
|
||||
{
|
||||
while (en.MoveNext())
|
||||
{
|
||||
Enqueue(en.Current);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return mSize; }
|
||||
}
|
||||
|
||||
/// Removes all items from the queue.
|
||||
public void Clear()
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
if (mHead < mTail)
|
||||
Array.Clear(mArray, mHead, mSize);
|
||||
else
|
||||
{
|
||||
Array.Clear(mArray, mHead, mArray.Count - mHead);
|
||||
Array.Clear(mArray, 0, mTail);
|
||||
}
|
||||
#endif
|
||||
mHead = 0;
|
||||
mTail = 0;
|
||||
mSize = 0;
|
||||
#if VERSION_QUEUE
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// CopyTo copies a collection into an Array, starting at a particular
|
||||
/// index into the array.
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
Debug.Assert((uint)arrayIndex <= (uint)array.Count);
|
||||
int arrayLen = array.Count;
|
||||
Debug.Assert(arrayLen >= mSize);
|
||||
|
||||
int numToCopy = (arrayLen - arrayIndex < mSize) ? (arrayLen - arrayIndex) : mSize;
|
||||
if (numToCopy == 0) return;
|
||||
|
||||
int firstPart = (mArray.Count - mHead < numToCopy) ? mArray.Count - mHead : numToCopy;
|
||||
Array.Copy(mArray, mHead, array, arrayIndex, firstPart);
|
||||
numToCopy -= firstPart;
|
||||
if (numToCopy > 0)
|
||||
{
|
||||
Array.Copy(mArray, 0, array, arrayIndex + mArray.Count - mHead, numToCopy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Adds item to the tail of the queue.
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
if (mSize == mArray.Count)
|
||||
{
|
||||
int newcapacity = (int)((int64)mArray.Count * (int64)cGrowFactor / 100);
|
||||
if (newcapacity < mArray.Count + cMinimumGrow)
|
||||
{
|
||||
newcapacity = mArray.Count + cMinimumGrow;
|
||||
}
|
||||
SetCapacity(newcapacity);
|
||||
}
|
||||
|
||||
mArray[mTail] = item;
|
||||
mTail = (mTail + 1) % (int_cosize)mArray.Count;
|
||||
mSize++;
|
||||
#if VERSION_QUEUE
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// GetEnumerator returns an IEnumerator over this Queue. This
|
||||
/// Enumerator will support removing.
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this);
|
||||
}
|
||||
|
||||
/// Removes the object at the head of the queue and returns it. If the queue
|
||||
/// is empty, this method simply returns null.
|
||||
public T Dequeue()
|
||||
{
|
||||
if (mSize == 0)
|
||||
//ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyQueue);
|
||||
Runtime.FatalError();
|
||||
|
||||
T removed = mArray[mHead];
|
||||
mArray[mHead] = default(T);
|
||||
mHead = (mHead + 1) % (int_cosize)mArray.Count;
|
||||
mSize--;
|
||||
#if VERSION_QUEUE
|
||||
mVersion++;
|
||||
#endif
|
||||
return removed;
|
||||
}
|
||||
|
||||
/// Returns the object at the head of the queue. The object remains in the
|
||||
/// queue. If the queue is empty, this method throws an
|
||||
/// InvalidOperationException.
|
||||
public T Peek()
|
||||
{
|
||||
Debug.Assert(mSize != 0);
|
||||
return mArray[mHead];
|
||||
}
|
||||
|
||||
/// Returns true if the queue contains at least one object equal to item.
|
||||
/// Equality is determined using item.Equals().
|
||||
public bool Contains(T item)
|
||||
{
|
||||
int index = mHead;
|
||||
int count = mSize;
|
||||
while (count-- > 0)
|
||||
{
|
||||
if (((Object)item) == null)
|
||||
{
|
||||
if (((Object)mArray[index]) == null)
|
||||
return true;
|
||||
}
|
||||
else if (mArray[index] != null && mArray[index] == item)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
index = (index + 1) % mArray.Count;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal T GetElement(int i)
|
||||
{
|
||||
return mArray[(mHead + i) % mArray.Count];
|
||||
}
|
||||
|
||||
/// Iterates over the objects in the queue, returning an array of the
|
||||
/// objects in the Queue, or an empty array if the queue is empty.
|
||||
/// The order of elements in the array is first in to last in, the same
|
||||
/// order produced by successive calls to Dequeue.
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] arr = new T[mSize];
|
||||
if (mSize == 0)
|
||||
return arr;
|
||||
|
||||
if (mHead < mTail)
|
||||
{
|
||||
Array.Copy(mArray, mHead, arr, 0, mSize);
|
||||
}else
|
||||
{
|
||||
Array.Copy(mArray, mHead, arr, 0, mArray.Count - mHead);
|
||||
Array.Copy(mArray, 0, arr, mArray.Count - mHead, mTail);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE Grows or shrinks the buffer to hold capacity objects. Capacity
|
||||
// must be >= _size.
|
||||
private void SetCapacity(int capacity)
|
||||
{
|
||||
T[] newarray = new T[capacity];
|
||||
if (mSize > 0)
|
||||
{
|
||||
if (mHead < mTail)
|
||||
{
|
||||
Array.Copy(mArray, mHead, newarray, 0, mSize);
|
||||
}else
|
||||
{
|
||||
Array.Copy(mArray, mHead, newarray, 0, mArray.Count - mHead);
|
||||
Array.Copy(mArray, 0, newarray, mArray.Count - mHead, mTail);
|
||||
}
|
||||
}
|
||||
|
||||
mArray = newarray;
|
||||
mHead = 0;
|
||||
mTail = (mSize == capacity) ? 0 : mSize;
|
||||
#if VERSION_QUEUE
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
int32 threshold = (int32)(((double)mArray.Count) * 0.9);
|
||||
if (mSize < threshold)
|
||||
{
|
||||
SetCapacity(mSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements an enumerator for a Queue. The enumerator uses the
|
||||
/// internal version number of the list to ensure that no modifications are
|
||||
/// made to the list while an enumeration is in progress.
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private Queue<T> mQueue;
|
||||
private int32 mIndex; // -1 = not started, -2 = ended/disposed
|
||||
#if VERSION_QUEUE
|
||||
private int32 mVersion;
|
||||
#endif
|
||||
private T mCurrentElement;
|
||||
|
||||
internal this(Queue<T> q)
|
||||
{
|
||||
mQueue = q;
|
||||
#if VERSION_QUEUE
|
||||
mVersion = mQueue.mVersion;
|
||||
#endif
|
||||
mIndex = -1;
|
||||
mCurrentElement = default(T);
|
||||
}
|
||||
|
||||
#if VERSION_QUEUE
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mQueue.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Dispose() mut
|
||||
{
|
||||
mIndex = -2;
|
||||
mCurrentElement = default(T);
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
#if VERSION_QUEUE
|
||||
CheckVersion();
|
||||
#endif
|
||||
if (mIndex == -2)
|
||||
return false;
|
||||
|
||||
mIndex++;
|
||||
|
||||
if (mIndex == mQueue.mSize)
|
||||
{
|
||||
mIndex = -2;
|
||||
mCurrentElement = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentElement = mQueue.GetElement(mIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mIndex < 0)
|
||||
{
|
||||
if (mIndex == -1)
|
||||
Runtime.FatalError("Enumeration not started");
|
||||
else
|
||||
Runtime.FatalError("Enumeration ended");
|
||||
}
|
||||
return mCurrentElement;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
#if VERSION_QUEUE
|
||||
CheckVersion();
|
||||
#endif
|
||||
mIndex = -1;
|
||||
mCurrentElement = default;
|
||||
}
|
||||
|
||||
public Result<T> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
326
BeefLibs/corlib/src/Collections/Generic/Sorter.bf
Normal file
326
BeefLibs/corlib/src/Collections/Generic/Sorter.bf
Normal file
|
@ -0,0 +1,326 @@
|
|||
// This file contains portions of code released by Microsoft under the MIT license as part
|
||||
// of an open-sourcing initiative in 2014 of the C# core libraries.
|
||||
// The original source was submitted to https://github.com/Microsoft/referencesource
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
struct Sorter<T, T2>
|
||||
{
|
||||
// This is the threshold where Introspective sort switches to Insertion sort.
|
||||
// Empirically, 16 seems to speed up most cases without slowing down others, at least for integers.
|
||||
// Large value types may benefit from a smaller number.
|
||||
const int IntrosortSizeThreshold = 16;
|
||||
|
||||
private T* keys;
|
||||
private T2* items;
|
||||
private int mCount;
|
||||
private Comparison<T> comparer;
|
||||
|
||||
internal this(T* keys, T2* items, int count, Comparison<T> comparer)
|
||||
{
|
||||
this.keys = keys;
|
||||
this.items = items;
|
||||
mCount = count;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
internal static int FloorLog2(int n)
|
||||
{
|
||||
int result = 0;
|
||||
int val = n;
|
||||
while (val >= 1)
|
||||
{
|
||||
result++;
|
||||
val = val / 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int GetMedian(int low, int hi)
|
||||
{
|
||||
// Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
|
||||
//Contract.Requires(low <= hi);
|
||||
//Contract.Assert( hi - low >= 0, "Length overflow!");
|
||||
return low + ((hi - low) >> 1);
|
||||
}
|
||||
|
||||
internal void SwapIfGreaterWithItems(int a, int b)
|
||||
{
|
||||
if (a != b)
|
||||
{
|
||||
if (comparer(keys[a], keys[b]) > 0)
|
||||
{
|
||||
T temp = keys[a];
|
||||
keys[a] = keys[b];
|
||||
keys[b] = temp;
|
||||
if ((items != null) && (sizeof(T2) != 0))
|
||||
{
|
||||
T2 item = items[a];
|
||||
items[a] = items[b];
|
||||
items[b] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Swap(int i, int j)
|
||||
{
|
||||
T t = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = t;
|
||||
|
||||
if (items != null)
|
||||
{
|
||||
T2 item = items[i];
|
||||
items[i] = items[j];
|
||||
items[j] = item;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Sort(int left, int length)
|
||||
{
|
||||
IntrospectiveSort(left, length);
|
||||
}
|
||||
|
||||
private void DepthLimitedQuickSort(int left, int right, int depthLimit)
|
||||
{
|
||||
// Can use the much faster jit helpers for array access.
|
||||
repeat
|
||||
{
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
Heapsort(left, right);
|
||||
return;
|
||||
}
|
||||
|
||||
int curLeft = left;
|
||||
int curRight = right;
|
||||
int curDepthLimit = depthLimit;
|
||||
|
||||
int i = curLeft;
|
||||
int j = curRight;
|
||||
|
||||
// pre-sort the low, middle (pivot), and high values in place.
|
||||
// this improves performance in the face of already sorted data, or
|
||||
// data that is made up of multiple sorted runs appended together.
|
||||
int middle = GetMedian(i, j);
|
||||
|
||||
SwapIfGreaterWithItems(i, middle); // swap the low with the mid point
|
||||
SwapIfGreaterWithItems(i, j); // swap the low with the high
|
||||
SwapIfGreaterWithItems(middle, j); // swap the middle with the high
|
||||
|
||||
T x = keys[middle];
|
||||
repeat
|
||||
{
|
||||
while (comparer(keys[i], x) < 0) i++;
|
||||
while (comparer(x, keys[j]) < 0) j--;
|
||||
|
||||
//Contract.Assert(i >= left && j <= right, "(i>=left && j<=right) Sort failed - Is your IComparer bogus?");
|
||||
if (i > j) break;
|
||||
if (i < j)
|
||||
{
|
||||
T key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
if (items != null)
|
||||
{
|
||||
T2 item = items[i];
|
||||
items[i] = items[j];
|
||||
items[j] = item;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
j--;
|
||||
} while (i <= j);
|
||||
|
||||
// The next iteration of the while loop is to "recursively" sort the larger half of the array and the
|
||||
// following calls recrusively sort the smaller half. So we subtrack one from depthLimit here so
|
||||
// both sorts see the new value.
|
||||
curDepthLimit--;
|
||||
|
||||
if (j - curLeft <= curRight - i)
|
||||
{
|
||||
if (curLeft < j) DepthLimitedQuickSort(curLeft, j, curDepthLimit);
|
||||
curLeft = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < curRight) DepthLimitedQuickSort(i, curRight, curDepthLimit);
|
||||
curRight = j;
|
||||
}
|
||||
} while (left < right);
|
||||
}
|
||||
|
||||
private void IntrospectiveSort(int left, int length)
|
||||
{
|
||||
if (length < 2)
|
||||
return;
|
||||
|
||||
IntroSort(left, length + left - 1, 2 * FloorLog2(mCount));
|
||||
}
|
||||
|
||||
private void IntroSort(int lo, int hi, int depthLimit)
|
||||
{
|
||||
int curHi = hi;
|
||||
int curDepthLimit = depthLimit;
|
||||
|
||||
while (curHi > lo)
|
||||
{
|
||||
int partitionSize = curHi - lo + 1;
|
||||
if (partitionSize <= IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo, curHi);
|
||||
return;
|
||||
}
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo, curHi-1);
|
||||
SwapIfGreaterWithItems(lo, curHi);
|
||||
SwapIfGreaterWithItems(curHi-1, curHi);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(lo, curHi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (curDepthLimit == 0)
|
||||
{
|
||||
Heapsort(lo, curHi);
|
||||
return;
|
||||
}
|
||||
curDepthLimit--;
|
||||
|
||||
int p = PickPivotAndPartition(lo, curHi);
|
||||
IntroSort(p + 1, curHi, curDepthLimit);
|
||||
curHi = p - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private int PickPivotAndPartition(int lo, int hi)
|
||||
{
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int mid = lo + (hi - lo) / 2;
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreaterWithItems(lo, mid);
|
||||
SwapIfGreaterWithItems(lo, hi);
|
||||
SwapIfGreaterWithItems(mid, hi);
|
||||
|
||||
T pivot = keys[mid];
|
||||
Swap(mid, hi - 1);
|
||||
int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
while (comparer(keys[++left], pivot) < 0) {}
|
||||
while (comparer(pivot, keys[--right]) < 0) {}
|
||||
|
||||
if(left >= right)
|
||||
break;
|
||||
|
||||
Swap(left, right);
|
||||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(left, (hi - 1));
|
||||
return left;
|
||||
}
|
||||
|
||||
private void Heapsort(int lo, int hi)
|
||||
{
|
||||
int n = hi - lo + 1;
|
||||
for (int i = n / 2; i >= 1; i = i - 1)
|
||||
{
|
||||
DownHeap(i, n, lo);
|
||||
}
|
||||
for (int i = n; i > 1; i = i - 1)
|
||||
{
|
||||
Swap(lo, lo + i - 1);
|
||||
|
||||
DownHeap(1, i - 1, lo);
|
||||
}
|
||||
}
|
||||
|
||||
private void DownHeap(int i, int n, int lo)
|
||||
{
|
||||
int curI = i;
|
||||
|
||||
T d = keys[lo + curI - 1];
|
||||
//T dt = (items != null) ? items[lo + i - 1] : null;
|
||||
T2* dt = (items != null) ? &items[lo + curI - 1] : null;
|
||||
int child;
|
||||
while (curI <= n / 2)
|
||||
{
|
||||
child = 2 * curI;
|
||||
if (child < n && comparer(keys[lo + child - 1], keys[lo + child]) < 0)
|
||||
{
|
||||
child++;
|
||||
}
|
||||
if (!(comparer(d, keys[lo + child - 1]) < 0))
|
||||
break;
|
||||
keys[lo + curI - 1] = keys[lo + child - 1];
|
||||
if(items != null)
|
||||
items[lo + curI - 1] = items[lo + child - 1];
|
||||
curI = child;
|
||||
}
|
||||
keys[lo + curI - 1] = d;
|
||||
if (items != null)
|
||||
items[lo + curI - 1] = *dt;
|
||||
}
|
||||
|
||||
private void InsertionSortZ(int lo, int hi)
|
||||
{
|
||||
int i, j;
|
||||
T t;
|
||||
T2 ti = ?;
|
||||
for (i = lo; i < hi; i++)
|
||||
{
|
||||
j = i;
|
||||
t = keys[i + 1];
|
||||
//ti = (items != null) ? items[i + 1] : null;
|
||||
if (items != null)
|
||||
ti = items[i + 1];
|
||||
while (j >= lo && comparer(t, keys[j]) < 0)
|
||||
{
|
||||
keys[j + 1] = keys[j];
|
||||
if(items != null)
|
||||
items[j + 1] = items[j];
|
||||
j--;
|
||||
}
|
||||
keys[j + 1] = t;
|
||||
if (items != null)
|
||||
items[j + 1] = ti;
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertionSort(int lo, int hi)
|
||||
{
|
||||
int i, j;
|
||||
T t;
|
||||
T2 ti = ?;
|
||||
for (i = lo; i < hi; i++)
|
||||
{
|
||||
j = i;
|
||||
t = keys[i + 1];
|
||||
if (items != null)
|
||||
ti = items[i + 1];
|
||||
while (j >= lo && comparer(t, keys[j]) < 0)
|
||||
{
|
||||
keys[j + 1] = keys[j];
|
||||
if(items != null)
|
||||
items[j + 1] = items[j];
|
||||
j--;
|
||||
}
|
||||
keys[j + 1] = t;
|
||||
if (items != null)
|
||||
items[j + 1] = ti;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
BeefLibs/corlib/src/Collections/IEnumerator.bf
Normal file
24
BeefLibs/corlib/src/Collections/IEnumerator.bf
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
interface IEnumerator<T>
|
||||
{
|
||||
Result<T> GetNext() mut;
|
||||
}
|
||||
|
||||
interface IResettable
|
||||
{
|
||||
void Reset() mut;
|
||||
}
|
||||
|
||||
interface IRefEnumerator<T> : IEnumerator<T>
|
||||
{
|
||||
Result<T*> GetNextRef() mut;
|
||||
}
|
||||
|
||||
concrete interface IEnumerable<T>
|
||||
{
|
||||
concrete IEnumerator<T> GetEnumerator();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue