mirror of
https://github.com/libretro/Mesen.git
synced 2025-01-08 09:52:02 +00:00
319 lines
7.7 KiB
C#
319 lines
7.7 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
|
|
namespace Be.Windows.Forms
|
|
{
|
|
internal class DataMap : ICollection, IEnumerable
|
|
{
|
|
readonly object _syncRoot = new object();
|
|
internal int _count;
|
|
internal DataBlock _firstBlock;
|
|
internal int _version;
|
|
|
|
public DataMap()
|
|
{
|
|
}
|
|
|
|
public DataMap(IEnumerable collection)
|
|
{
|
|
if (collection == null)
|
|
{
|
|
throw new ArgumentNullException("collection");
|
|
}
|
|
|
|
foreach (DataBlock item in collection)
|
|
{
|
|
AddLast(item);
|
|
}
|
|
}
|
|
|
|
public DataBlock FirstBlock
|
|
{
|
|
get
|
|
{
|
|
return _firstBlock;
|
|
}
|
|
}
|
|
|
|
public void AddAfter(DataBlock block, DataBlock newBlock)
|
|
{
|
|
AddAfterInternal(block, newBlock);
|
|
}
|
|
|
|
public void AddBefore(DataBlock block, DataBlock newBlock)
|
|
{
|
|
AddBeforeInternal(block, newBlock);
|
|
}
|
|
|
|
public void AddFirst(DataBlock block)
|
|
{
|
|
if (_firstBlock == null)
|
|
{
|
|
AddBlockToEmptyMap(block);
|
|
}
|
|
else
|
|
{
|
|
AddBeforeInternal(_firstBlock, block);
|
|
}
|
|
}
|
|
|
|
public void AddLast(DataBlock block)
|
|
{
|
|
if (_firstBlock == null)
|
|
{
|
|
AddBlockToEmptyMap(block);
|
|
}
|
|
else
|
|
{
|
|
AddAfterInternal(GetLastBlock(), block);
|
|
}
|
|
}
|
|
|
|
public void Remove(DataBlock block)
|
|
{
|
|
RemoveInternal(block);
|
|
}
|
|
|
|
public void RemoveFirst()
|
|
{
|
|
if (_firstBlock == null)
|
|
{
|
|
throw new InvalidOperationException("The collection is empty.");
|
|
}
|
|
RemoveInternal(_firstBlock);
|
|
}
|
|
|
|
public void RemoveLast()
|
|
{
|
|
if (_firstBlock == null)
|
|
{
|
|
throw new InvalidOperationException("The collection is empty.");
|
|
}
|
|
RemoveInternal(GetLastBlock());
|
|
}
|
|
|
|
public DataBlock Replace(DataBlock block, DataBlock newBlock)
|
|
{
|
|
AddAfterInternal(block, newBlock);
|
|
RemoveInternal(block);
|
|
return newBlock;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
DataBlock block = FirstBlock;
|
|
while (block != null)
|
|
{
|
|
DataBlock nextBlock = block.NextBlock;
|
|
InvalidateBlock(block);
|
|
block = nextBlock;
|
|
}
|
|
_firstBlock = null;
|
|
_count = 0;
|
|
_version++;
|
|
}
|
|
|
|
void AddAfterInternal(DataBlock block, DataBlock newBlock)
|
|
{
|
|
newBlock._previousBlock = block;
|
|
newBlock._nextBlock = block._nextBlock;
|
|
newBlock._map = this;
|
|
|
|
if (block._nextBlock != null)
|
|
{
|
|
block._nextBlock._previousBlock = newBlock;
|
|
}
|
|
block._nextBlock = newBlock;
|
|
|
|
this._version++;
|
|
this._count++;
|
|
}
|
|
|
|
void AddBeforeInternal(DataBlock block, DataBlock newBlock)
|
|
{
|
|
newBlock._nextBlock = block;
|
|
newBlock._previousBlock = block._previousBlock;
|
|
newBlock._map = this;
|
|
|
|
if (block._previousBlock != null)
|
|
{
|
|
block._previousBlock._nextBlock = newBlock;
|
|
}
|
|
block._previousBlock = newBlock;
|
|
|
|
if (_firstBlock == block)
|
|
{
|
|
_firstBlock = newBlock;
|
|
}
|
|
this._version++;
|
|
this._count++;
|
|
}
|
|
|
|
void RemoveInternal(DataBlock block)
|
|
{
|
|
DataBlock previousBlock = block._previousBlock;
|
|
DataBlock nextBlock = block._nextBlock;
|
|
|
|
if (previousBlock != null)
|
|
{
|
|
previousBlock._nextBlock = nextBlock;
|
|
}
|
|
|
|
if (nextBlock != null)
|
|
{
|
|
nextBlock._previousBlock = previousBlock;
|
|
}
|
|
|
|
if (_firstBlock == block)
|
|
{
|
|
_firstBlock = nextBlock;
|
|
}
|
|
|
|
InvalidateBlock(block);
|
|
|
|
_count--;
|
|
_version++;
|
|
}
|
|
|
|
DataBlock GetLastBlock()
|
|
{
|
|
DataBlock lastBlock = null;
|
|
for (DataBlock block = FirstBlock; block != null; block = block.NextBlock)
|
|
{
|
|
lastBlock = block;
|
|
}
|
|
return lastBlock;
|
|
}
|
|
|
|
void InvalidateBlock(DataBlock block)
|
|
{
|
|
block._map = null;
|
|
block._nextBlock = null;
|
|
block._previousBlock = null;
|
|
}
|
|
|
|
void AddBlockToEmptyMap(DataBlock block)
|
|
{
|
|
block._map = this;
|
|
block._nextBlock = null;
|
|
block._previousBlock = null;
|
|
|
|
_firstBlock = block;
|
|
_version++;
|
|
_count++;
|
|
}
|
|
|
|
#region ICollection Members
|
|
public void CopyTo(Array array, int index)
|
|
{
|
|
DataBlock[] blockArray = array as DataBlock[];
|
|
for (DataBlock block = FirstBlock; block != null; block = block.NextBlock)
|
|
{
|
|
blockArray[index++] = block;
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
return _count;
|
|
}
|
|
}
|
|
|
|
public bool IsSynchronized
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public object SyncRoot
|
|
{
|
|
get
|
|
{
|
|
return _syncRoot;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region IEnumerable Members
|
|
public IEnumerator GetEnumerator()
|
|
{
|
|
return new Enumerator(this);
|
|
}
|
|
#endregion
|
|
|
|
#region Enumerator Nested Type
|
|
internal class Enumerator : IEnumerator, IDisposable
|
|
{
|
|
DataMap _map;
|
|
DataBlock _current;
|
|
int _index;
|
|
int _version;
|
|
|
|
internal Enumerator(DataMap map)
|
|
{
|
|
_map = map;
|
|
_version = map._version;
|
|
_current = null;
|
|
_index = -1;
|
|
}
|
|
|
|
object IEnumerator.Current
|
|
{
|
|
get
|
|
{
|
|
if (_index < 0 || _index > _map.Count)
|
|
{
|
|
throw new InvalidOperationException("Enumerator is positioned before the first element or after the last element of the collection.");
|
|
}
|
|
return _current;
|
|
}
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
if (this._version != _map._version)
|
|
{
|
|
throw new InvalidOperationException("Collection was modified after the enumerator was instantiated.");
|
|
}
|
|
|
|
if (_index >= _map.Count)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (++_index == 0)
|
|
{
|
|
_current = _map.FirstBlock;
|
|
}
|
|
else
|
|
{
|
|
_current = _current.NextBlock;
|
|
}
|
|
|
|
return (_index < _map.Count);
|
|
}
|
|
|
|
void IEnumerator.Reset()
|
|
{
|
|
if (this._version != this._map._version)
|
|
{
|
|
throw new InvalidOperationException("Collection was modified after the enumerator was instantiated.");
|
|
}
|
|
|
|
this._index = -1;
|
|
this._current = null;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|