wasSharp – Blame information for rev 54
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
10 | office | 1 | /////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
||
3 | // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
||
4 | // rights of fair usage, the disclaimer and warranty conditions. // |
||
5 | /////////////////////////////////////////////////////////////////////////// |
||
6 | |||
7 | using System; |
||
39 | office | 8 | using System.Threading; |
10 | office | 9 | using System.Collections; |
10 | using System.Collections.Generic; |
||
11 | using System.Collections.Specialized; |
||
12 | using System.Linq; |
||
13 | |||
14 | namespace wasSharp.Collections.Specialized |
||
15 | { |
||
16 | /////////////////////////////////////////////////////////////////////////// |
||
17 | // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
||
18 | /////////////////////////////////////////////////////////////////////////// |
||
19 | /// <summary> |
||
20 | /// An implementation of an observable HashSet. |
||
21 | /// </summary> |
||
22 | /// <typeparam name="T">the object type</typeparam> |
||
54 | office | 23 | public class ObservableConcurrentHashSet<T> : ICollection<T>, INotifyCollectionChanged, IEnumerable<T> |
10 | office | 24 | { |
44 | office | 25 | private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
10 | office | 26 | private readonly HashSet<T> store = new HashSet<T>(); |
27 | |||
54 | office | 28 | public ObservableConcurrentHashSet(HashSet<T> set) |
10 | office | 29 | { |
44 | office | 30 | _lock.EnterWriteLock(); |
31 | try |
||
32 | { |
||
33 | UnionWith(set); |
||
34 | } |
||
35 | finally |
||
36 | { |
||
37 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
38 | } |
||
10 | office | 39 | } |
40 | |||
54 | office | 41 | public ObservableConcurrentHashSet() |
10 | office | 42 | { |
43 | } |
||
44 | |||
54 | office | 45 | public ObservableConcurrentHashSet(T item) |
10 | office | 46 | { |
44 | office | 47 | _lock.EnterWriteLock(); |
48 | try |
||
49 | { |
||
50 | Add(item); |
||
51 | } |
||
52 | finally |
||
53 | { |
||
54 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
55 | } |
||
10 | office | 56 | } |
57 | |||
54 | office | 58 | public ObservableConcurrentHashSet(ObservableConcurrentHashSet<T> other) |
10 | office | 59 | { |
44 | office | 60 | _lock.EnterWriteLock(); |
61 | try |
||
62 | { |
||
63 | UnionWith(other); |
||
64 | } |
||
65 | finally |
||
66 | { |
||
67 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
68 | } |
||
10 | office | 69 | } |
70 | |||
54 | office | 71 | public ObservableConcurrentHashSet(IEnumerable<T> list) |
10 | office | 72 | { |
44 | office | 73 | _lock.EnterWriteLock(); |
74 | try |
||
75 | { |
||
76 | UnionWith(list); |
||
77 | } |
||
78 | finally |
||
79 | { |
||
80 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
81 | } |
||
10 | office | 82 | } |
83 | |||
84 | public bool IsVirgin { get; private set; } = true; |
||
85 | |||
86 | public IEnumerator<T> GetEnumerator() |
||
87 | { |
||
44 | office | 88 | _lock.EnterReadLock(); |
89 | try |
||
90 | { |
||
91 | using (var enumerator = store.GetEnumerator()) |
||
92 | { |
||
93 | while (enumerator.MoveNext()) |
||
94 | yield return enumerator.Current; |
||
95 | } |
||
96 | } |
||
97 | finally |
||
98 | { |
||
99 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
||
100 | } |
||
10 | office | 101 | } |
102 | |||
103 | IEnumerator IEnumerable.GetEnumerator() |
||
104 | { |
||
44 | office | 105 | _lock.EnterReadLock(); |
106 | try |
||
107 | { |
||
108 | using (var enumerator = store.GetEnumerator()) |
||
109 | { |
||
110 | while (enumerator.MoveNext()) |
||
111 | yield return enumerator.Current; |
||
112 | } |
||
113 | } |
||
114 | finally |
||
115 | { |
||
116 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
||
117 | } |
||
10 | office | 118 | } |
119 | |||
120 | public void Add(T item) |
||
121 | { |
||
44 | office | 122 | _lock.EnterWriteLock(); |
123 | try |
||
124 | { |
||
125 | store.Add(item); |
||
126 | } |
||
127 | finally |
||
128 | { |
||
129 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
130 | } |
||
10 | office | 131 | IsVirgin = false; |
132 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); |
||
133 | } |
||
134 | |||
135 | public void Clear() |
||
136 | { |
||
44 | office | 137 | _lock.EnterWriteLock(); |
138 | try |
||
139 | { |
||
140 | store.Clear(); |
||
141 | } |
||
142 | finally |
||
143 | { |
||
144 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
145 | } |
||
10 | office | 146 | if (!IsVirgin) |
147 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
||
148 | IsVirgin = false; |
||
149 | } |
||
150 | |||
151 | public bool Contains(T item) |
||
152 | { |
||
44 | office | 153 | _lock.EnterReadLock(); |
154 | try |
||
155 | { |
||
156 | return store.Contains(item); |
||
157 | } |
||
158 | finally |
||
159 | { |
||
160 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
||
161 | } |
||
10 | office | 162 | } |
163 | |||
164 | public void CopyTo(T[] array, int arrayIndex) |
||
165 | { |
||
44 | office | 166 | _lock.EnterReadLock(); |
167 | try |
||
168 | { |
||
169 | store.CopyTo(array, arrayIndex); |
||
170 | } |
||
171 | finally |
||
172 | { |
||
173 | if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
||
174 | } |
||
10 | office | 175 | } |
176 | |||
177 | public bool Remove(T item) |
||
178 | { |
||
44 | office | 179 | _lock.EnterWriteLock(); |
180 | bool removed; |
||
181 | try |
||
182 | { |
||
183 | removed = store.Remove(item); |
||
184 | } |
||
185 | finally |
||
186 | { |
||
187 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
188 | } |
||
10 | office | 189 | IsVirgin = false; |
190 | if (removed) |
||
191 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
||
192 | return removed; |
||
193 | } |
||
194 | |||
54 | office | 195 | public int Count => store.Count(); |
196 | |||
10 | office | 197 | public bool IsReadOnly => false; |
198 | |||
199 | public event NotifyCollectionChangedEventHandler CollectionChanged; |
||
200 | |||
201 | public void UnionWith(IEnumerable<T> list) |
||
202 | { |
||
203 | var added = new List<T>(list.Except(store)); |
||
44 | office | 204 | _lock.EnterWriteLock(); |
205 | try |
||
206 | { |
||
207 | store.UnionWith(added); |
||
208 | } |
||
209 | finally |
||
210 | { |
||
211 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
212 | } |
||
10 | office | 213 | if (!IsVirgin && added.Any()) |
214 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added)); |
||
215 | IsVirgin = false; |
||
216 | } |
||
217 | |||
218 | private void OnCollectionChanged(NotifyCollectionChangedEventArgs args) |
||
219 | { |
||
220 | CollectionChanged?.Invoke(this, args); |
||
221 | } |
||
222 | |||
223 | public void ExceptWith(IEnumerable<T> list) |
||
224 | { |
||
225 | var removed = new List<T>(list.Intersect(store)); |
||
44 | office | 226 | _lock.EnterWriteLock(); |
227 | try |
||
228 | { |
||
229 | store.ExceptWith(removed); |
||
230 | } |
||
231 | finally |
||
232 | { |
||
233 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
234 | } |
||
10 | office | 235 | if (!IsVirgin && removed.Any()) |
236 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
||
237 | removed)); |
||
238 | IsVirgin = false; |
||
239 | } |
||
240 | |||
241 | public void RemoveWhere(Func<T, bool> func) |
||
242 | { |
||
243 | var removed = new List<T>(store.Where(func)); |
||
44 | office | 244 | _lock.EnterWriteLock(); |
245 | try |
||
246 | { |
||
247 | store.ExceptWith(removed); |
||
248 | } |
||
249 | finally |
||
250 | { |
||
251 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
252 | } |
||
10 | office | 253 | if (!IsVirgin && removed.Any()) |
254 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
||
255 | removed)); |
||
256 | IsVirgin = false; |
||
257 | } |
||
23 | office | 258 | |
259 | public IEnumerable<T> AsEnumerable() |
||
260 | { |
||
44 | office | 261 | _lock.EnterWriteLock(); |
262 | try |
||
263 | { |
||
264 | return store.AsEnumerable(); |
||
265 | } |
||
266 | finally |
||
267 | { |
||
268 | if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
||
269 | } |
||
23 | office | 270 | } |
10 | office | 271 | } |
27 | office | 272 | } |