1 // OpenTween - Client of Twitter
2 // Copyright (c) 2015 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
25 using System.Collections;
26 using System.Collections.Generic;
32 /// インデックスでのアクセスが可能なソートされた重複のないコレクション
34 public class IndexedSortedSet<T> : ISet<T>, IReadOnlyList<T>
36 private readonly List<T> innerList;
37 private readonly IComparer<T> comparer;
40 => this.innerList.Count;
42 public bool IsReadOnly
45 public T this[int index]
46 => this.innerList[index];
48 public IndexedSortedSet()
49 : this(Enumerable.Empty<T>(), Comparer<T>.Default)
53 public IndexedSortedSet(IComparer<T> comparer)
54 : this(Enumerable.Empty<T>(), comparer)
58 public IndexedSortedSet(IEnumerable<T> items)
59 : this(items, Comparer<T>.Default)
63 public IndexedSortedSet(IEnumerable<T> items, IComparer<T> comparer)
65 this.innerList = new List<T>(items.OrderBy(x => x, comparer));
66 this.comparer = comparer;
69 public bool Add(T item)
71 if (this.innerList.Count == 0)
73 this.innerList.Add(item);
77 var index = this.innerList.BinarySearch(item, comparer);
81 // ~index → item の次に大きい要素のインデックス
82 this.innerList.Insert(~index, item);
87 void ICollection<T>.Add(T item)
90 public bool Remove(T item)
92 var index = this.IndexOf(item);
96 this.innerList.RemoveAt(index);
102 => this.innerList.Clear();
104 public bool Contains(T item)
105 => this.IndexOf(item) != -1;
107 public int IndexOf(T item)
109 var index = this.innerList.BinarySearch(item, this.comparer);
111 return index < 0 ? -1 : index;
114 public void RemoveAt(int index)
115 => this.innerList.RemoveAt(index);
117 public void CopyTo(T[] array, int arrayIndex)
120 throw new ArgumentNullException(nameof(array));
122 throw new ArgumentOutOfRangeException(nameof(arrayIndex));
123 if (arrayIndex >= array.Length)
124 throw new ArgumentException($"{nameof(arrayIndex)} is equal to or greater than {nameof(array)}.Length.", nameof(arrayIndex));
125 if (array.Length - arrayIndex < this.Count)
126 throw new ArgumentException("The destination array is too small.", nameof(array));
128 foreach (var pair in this)
129 array[arrayIndex++] = pair;
132 public IEnumerator<T> GetEnumerator()
133 => this.innerList.GetEnumerator();
135 IEnumerator IEnumerable.GetEnumerator()
136 => this.GetEnumerator();
138 public void UnionWith(IEnumerable<T> other)
140 foreach (var item in other)
144 public void IntersectWith(IEnumerable<T> other)
146 var containsMark = new bool[this.Count];
148 foreach (var item in other)
150 var index = this.IndexOf(item);
152 containsMark[index] = true;
155 foreach (var index in MyCommon.CountDown(this.Count - 1, 0))
157 if (!containsMark[index])
158 this.RemoveAt(index);
162 public void ExceptWith(IEnumerable<T> other)
164 foreach (var item in other)
168 public void SymmetricExceptWith(IEnumerable<T> other)
170 foreach (var item in other)
172 if (this.Contains(item))
179 public bool IsSubsetOf(IEnumerable<T> other)
181 var containsMark = new bool[this.Count];
183 foreach (var item in other)
185 var index = this.IndexOf(item);
187 containsMark[index] = true;
190 return containsMark.All(x => x == true);
193 public bool IsSupersetOf(IEnumerable<T> other)
195 foreach (var item in other)
197 if (!this.Contains(item))
204 public bool IsProperSupersetOf(IEnumerable<T> other)
205 => !this.SetEquals(other) && this.IsSupersetOf(other);
207 public bool IsProperSubsetOf(IEnumerable<T> other)
208 => !this.SetEquals(other) && this.IsSubsetOf(other);
210 public bool Overlaps(IEnumerable<T> other)
212 foreach (var item in other)
214 if (this.Contains(item))
221 public bool SetEquals(IEnumerable<T> other)
223 var containsMark = new bool[this.Count];
225 foreach (var item in other)
227 var index = this.IndexOf(item);
231 containsMark[index] = true;
234 return containsMark.All(x => x == true);