/* https://github.com/mbuchetics/RangeTree よりコピペ。このファイルのみMITライセンスに従います */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FooEditEngine { /// /// マーカーを表す /// internal interface IRange { /// /// マーカーの開始位置。-1を設定した場合、そのマーカーはレタリングされません /// int start { get; set; } /// /// マーカーの長さ。0を設定した場合、そのマーカーはレタリングされません /// int length { get; set; } } internal sealed class RangeCollection : IEnumerable where T : IRange { List collection; public RangeCollection() : this(null) { } public RangeCollection(IEnumerable collection) { if (collection == null) this.collection = new List(); else this.collection = new List(collection); } public T this[int i] { get { return this.collection[i]; } set { this.collection[i] = value; } } public int Count { get { return this.collection.Count; } } public void Add(T item) { this.collection.Add(item); for (int i = this.collection.Count - 1; i >= 0; i--) { if (i > 0 && this.collection[i].start < this.collection[i - 1].start) { T temp = this.collection[i]; this.collection[i] = this.collection[i - 1]; this.collection[i - 1] = temp; } else { break; } } } public void Remove(int start, int length) { if (this.collection.Count == 0) return; int at = this.IndexOf(start); int endAt = this.IndexOf(start + length - 1); if(at != -1 && endAt != -1) { for (int i = endAt; i >= at; i--) { this.collection.RemoveAt(i); } } else if (at != -1) { this.collection.RemoveAt(at); } else if(endAt != -1) { this.collection.RemoveAt(endAt); } } public void RemoveNearest(int start, int length) { if (this.collection.Count == 0) return; int nearAt; int at = this.IndexOfNearest(start, out nearAt); if (at == -1) at = nearAt; int nearEndAt; int endAt = this.IndexOfNearest(start + length - 1, out nearEndAt); if (endAt == -1) endAt = nearEndAt; int end = start + length - 1; for (int i = endAt; i >= at; i--) { int markerEnd = this.collection[i].start + this.collection[i].length - 1; if (this.collection[i].start >= start && markerEnd <= end || markerEnd >= start && markerEnd <= end || this.collection[i].start >= start && this.collection[i].start <= end || this.collection[i].start < start && markerEnd > end) this.collection.RemoveAt(i); } } public void RemoveAt(int index) { this.collection.RemoveAt(index); } public int IndexOf(int start) { int dummy; return this.IndexOfNearest(start, out dummy); } int IndexOfNearest(int start,out int nearIndex) { nearIndex = -1; int left = 0, right = this.collection.Count - 1, mid; while (left <= right) { mid = (left + right) / 2; T item = this.collection[mid]; if (start >= item.start && start < item.start + item.length) { return mid; } if (start < item.start) { right = mid - 1; } else { left = mid + 1; } } System.Diagnostics.Debug.Assert(left >= 0 || right >= 0); nearIndex = left >= 0 ? left : right; if (nearIndex > this.collection.Count - 1) nearIndex = right; return -1; } public IEnumerable Get(int index) { int at = this.IndexOf(index); if (at == -1) yield break; yield return this.collection[at]; } public IEnumerable Get(int start, int length) { int nearAt; int at = this.IndexOfNearest(start,out nearAt); if (at == -1) at = nearAt; if (at == -1) yield break; int end = start + length - 1; for (int i = at; i < this.collection.Count; i++) { int markerEnd = this.collection[i].start + this.collection[i].length - 1; if (this.collection[i].start >= start && markerEnd <= end || markerEnd >= start && markerEnd <= end || this.collection[i].start >= start && this.collection[i].start <= end || this.collection[i].start < start && markerEnd > end) yield return this.collection[i]; else if (this.collection[i].start > start + length) yield break; } } public void Clear() { this.collection.Clear(); } public IEnumerator GetEnumerator() { foreach (T item in this.collection) yield return item; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } }