-
Notifications
You must be signed in to change notification settings - Fork 284
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Collections.ObjectModel; | ||
using System.Text; | ||
|
||
namespace NBTExplorer | ||
{ | ||
public class SnapshotState<T> : IDisposable | ||
{ | ||
private SnapshotList<T> _list; | ||
|
||
internal SnapshotState (SnapshotList<T> list) | ||
{ | ||
_list = list; | ||
_list.Begin(); | ||
} | ||
|
||
public void Dispose () | ||
{ | ||
_list.End(); | ||
GC.SuppressFinalize(this); | ||
} | ||
} | ||
|
||
public class SnapshotList<T> : Collection<T> | ||
{ | ||
private IList<T> _snapshot; | ||
private IList<T> _recycled; | ||
private int _snapshots; | ||
|
||
public SnapshotList () | ||
: base(new ProxyList<T>()) | ||
{ } | ||
|
||
public SnapshotList (IList<T> list) | ||
: base(new ProxyList<T>(new List<T>(list))) | ||
{ } | ||
|
||
public SnapshotList (int capacity) | ||
: base(new ProxyList<T>(new List<T>(capacity))) | ||
{ } | ||
|
||
private new ProxyList<T> Items | ||
{ | ||
get { return base.Items as ProxyList<T>; } | ||
} | ||
|
||
public IList<T> Begin () | ||
{ | ||
Modified(); | ||
_snapshot = Items.InnerList; | ||
_snapshots++; | ||
return _snapshot; | ||
} | ||
|
||
public void End () | ||
{ | ||
_snapshots = Math.Max(0, _snapshots - 1); | ||
if (_snapshot == null) | ||
return; | ||
|
||
// The backing array was copied, keep around the old array | ||
if (_snapshot != Items.InnerList && _snapshots == 0) { | ||
_recycled = _snapshot; | ||
_recycled.Clear(); | ||
//for (int i = 0, n = _recycled.Count; i < n; i++) | ||
// _recycled[i] = default(T); | ||
} | ||
|
||
_snapshot = null; | ||
} | ||
|
||
public SnapshotState<T> Snapshot () | ||
{ | ||
return new SnapshotState<T>(this); | ||
} | ||
|
||
private void Modified () | ||
{ | ||
if (_snapshot == null || _snapshot != Items.InnerList) | ||
return; | ||
|
||
// Snapshot is in use, copy backing array to recycled array or create new backing array | ||
if (_recycled != null) { | ||
for (int i = 0; i < Count; i++) | ||
_recycled.Add(Items[i]); | ||
Items.InnerList = _recycled; | ||
_recycled = null; | ||
} | ||
else | ||
Resize(Items.Count); | ||
} | ||
|
||
private void Resize (int newSize) | ||
{ | ||
IList<T> oldList = Items.InnerList; | ||
List<T> newList = new List<T>(newSize); | ||
for (int i = 0, n = oldList.Count; i < n; i++) | ||
newList.Add(oldList[i]); | ||
|
||
Items.InnerList = newList; | ||
} | ||
|
||
protected override void InsertItem (int index, T item) | ||
{ | ||
Modified(); | ||
base.InsertItem(index, item); | ||
} | ||
|
||
protected override void SetItem (int index, T item) | ||
{ | ||
Modified(); | ||
base.SetItem(index, item); | ||
} | ||
|
||
protected override void RemoveItem (int index) | ||
{ | ||
Modified(); | ||
base.RemoveItem(index); | ||
} | ||
|
||
protected override void ClearItems () | ||
{ | ||
Modified(); | ||
base.ClearItems(); | ||
} | ||
|
||
private class ProxyList<K> : IList<K> | ||
{ | ||
public IList<K> InnerList { get; set; } | ||
|
||
public ProxyList () | ||
{ | ||
InnerList = new List<K>(); | ||
} | ||
|
||
public ProxyList (IList<K> list) | ||
{ | ||
InnerList = list; | ||
} | ||
|
||
public int IndexOf (K item) | ||
{ | ||
return InnerList.IndexOf(item); | ||
} | ||
|
||
public void Insert (int index, K item) | ||
{ | ||
InnerList.Insert(index, item); | ||
} | ||
|
||
public void RemoveAt (int index) | ||
{ | ||
InnerList.RemoveAt(index); | ||
} | ||
|
||
public K this[int index] | ||
{ | ||
get { return InnerList[index]; } | ||
set { InnerList[index] = value; } | ||
} | ||
|
||
public void Add (K item) | ||
{ | ||
InnerList.Add(item); | ||
} | ||
|
||
public void Clear () | ||
{ | ||
InnerList.Clear(); | ||
} | ||
|
||
public bool Contains (K item) | ||
{ | ||
return InnerList.Contains(item); | ||
} | ||
|
||
public void CopyTo (K[] array, int arrayIndex) | ||
{ | ||
InnerList.CopyTo(array, arrayIndex); | ||
} | ||
|
||
public int Count | ||
{ | ||
get { return InnerList.Count; } | ||
} | ||
|
||
public bool IsReadOnly | ||
{ | ||
get { return InnerList.IsReadOnly; } | ||
} | ||
|
||
public bool Remove (K item) | ||
{ | ||
return InnerList.Remove(item); | ||
} | ||
|
||
public IEnumerator<K> GetEnumerator () | ||
{ | ||
return InnerList.GetEnumerator(); | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator () | ||
{ | ||
return InnerList.GetEnumerator(); | ||
} | ||
} | ||
} | ||
} |