Skip to content

Commit 1c07f3a

Browse files
Abstracted collections.
1 parent 55d0bc5 commit 1c07f3a

2 files changed

Lines changed: 135 additions & 116 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using Open.Threading;
2+
using System;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using System.Collections.Immutable;
6+
using System.Linq;
7+
using System.Threading;
8+
9+
namespace Open.Collections.Synchronized;
10+
11+
public class TrackedCollectionWrapper<T, TCollection>
12+
: ModificationSynchronizedBase, ICollection<T>
13+
where TCollection : class, ICollection<T>
14+
{
15+
protected TCollection InternalSource;
16+
17+
public TrackedCollectionWrapper(TCollection collection, ModificationSynchronizer? sync = null)
18+
: base(sync) => InternalSource = collection ?? throw new ArgumentNullException(nameof(collection));
19+
20+
public TrackedCollectionWrapper(TCollection collection, out ModificationSynchronizer sync)
21+
: base(out sync) => InternalSource = collection ?? throw new ArgumentNullException(nameof(collection));
22+
23+
protected override ModificationSynchronizer InitSync(object? sync = null)
24+
{
25+
_syncOwned = true;
26+
return new ReadWriteModificationSynchronizer(sync as ReaderWriterLockSlim);
27+
}
28+
29+
protected override void OnDispose()
30+
{
31+
base.OnDispose();
32+
Nullify(ref InternalSource); // Eliminate risk from wrapper.
33+
}
34+
35+
/// <inheritdoc />
36+
public int Count
37+
=> Sync!.Reading(() =>
38+
{
39+
AssertIsAlive();
40+
return InternalSource.Count;
41+
});
42+
43+
protected virtual void AddInternal(T item)
44+
=> InternalSource.Add(item);
45+
46+
/// <inheritdoc />
47+
public void Add(T item)
48+
=> Sync!.Modifying(() => AssertIsAlive(), () =>
49+
{
50+
AddInternal(item);
51+
return true;
52+
});
53+
54+
public void AddRange(IEnumerable<T> items)
55+
{
56+
if (items is null) return;
57+
IReadOnlyList<T> enumerable = items switch
58+
{
59+
IImmutableList<T> i => i,
60+
T[] a => a,
61+
_ => items.ToArray(),
62+
63+
};
64+
65+
if (enumerable.Count == 0)
66+
return;
67+
68+
Sync!.Modifying(() => AssertIsAlive(), () =>
69+
{
70+
foreach (var item in enumerable)
71+
AddInternal(item);
72+
return true;
73+
});
74+
}
75+
76+
protected virtual void ClearInternal()
77+
=> InternalSource.Clear();
78+
79+
/// <inheritdoc />
80+
public void Clear()
81+
=> Sync!.Modifying(
82+
() => AssertIsAlive() && InternalSource.Count != 0,
83+
() =>
84+
{
85+
int count = Count;
86+
bool hasItems = count != 0;
87+
if (hasItems) ClearInternal();
88+
return hasItems;
89+
});
90+
91+
/// <inheritdoc />
92+
public bool Contains(T item)
93+
=> Sync!.Reading(() => AssertIsAlive() && InternalSource.Contains(item));
94+
95+
/// <inheritdoc />
96+
public void CopyTo(T[] array, int arrayIndex)
97+
=> Sync!.Reading(() =>
98+
{
99+
AssertIsAlive();
100+
InternalSource.CopyTo(array, arrayIndex);
101+
});
102+
103+
/// <inheritdoc />
104+
public virtual bool Remove(T item)
105+
=> Sync!.Modifying(
106+
() => AssertIsAlive(),
107+
() => InternalSource.Remove(item));
108+
109+
protected virtual IEnumerator<T> GetEnumeratorInternal()
110+
=> InternalSource.GetEnumerator();
111+
112+
/// <inheritdoc />
113+
public IEnumerator<T> GetEnumerator()
114+
=> Sync!.Reading(() =>
115+
{
116+
AssertIsAlive();
117+
return GetEnumeratorInternal();
118+
});
119+
120+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
121+
}

source/Synchronized/TrackedList.cs

Lines changed: 14 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
using Open.Threading;
22
using System;
3-
using System.Collections;
43
using System.Collections.Generic;
5-
using System.Collections.Immutable;
6-
using System.Linq;
7-
using System.Runtime.CompilerServices;
8-
using System.Threading;
94

105
namespace Open.Collections.Synchronized;
116

12-
public class TrackedList<T> : ModificationSynchronizedBase, IList<T>
7+
public class TrackedList<T> : TrackedCollectionWrapper<T, IList<T>>, IList<T>
138
{
14-
protected List<T> _source = new();
15-
16-
public TrackedList(ModificationSynchronizer? sync = null) : base(sync)
17-
{
18-
}
19-
20-
public TrackedList(out ModificationSynchronizer sync) : base(out sync)
21-
{
22-
}
23-
24-
protected override ModificationSynchronizer InitSync(object? sync = null)
9+
public TrackedList(ModificationSynchronizer? sync = null) : base(new List<T>(), sync)
2510
{
26-
_syncOwned = true;
27-
return new ReadWriteModificationSynchronizer(sync as ReaderWriterLockSlim);
2811
}
2912

30-
protected override void OnDispose()
13+
public TrackedList(out ModificationSynchronizer sync) : base(new List<T>(), out sync)
3114
{
32-
base.OnDispose();
33-
Nullify(ref _source)?.Clear();
3415
}
3516

3617
/// <inheritdoc />
@@ -39,7 +20,7 @@ public T this[int index]
3920
get => Sync!.Reading(() =>
4021
{
4122
AssertIsAlive();
42-
return _source[index];
23+
return InternalSource[index];
4324
});
4425

4526
set => SetValue(index, value);
@@ -53,33 +34,13 @@ public bool SetValue(int index, T value)
5334
private bool SetValueInternal(int index, T value)
5435
{
5536
bool changing
56-
= index >= _source.Count
57-
|| !(_source[index]?.Equals(value) ?? value is null);
37+
= index >= InternalSource.Count
38+
|| !(InternalSource[index]?.Equals(value) ?? value is null);
5839
if (changing)
59-
_source[index] = value;
40+
InternalSource[index] = value;
6041
return changing;
6142
}
6243

63-
/// <inheritdoc />
64-
public int Count
65-
=> Sync!.Reading(() =>
66-
{
67-
AssertIsAlive();
68-
return _source.Count;
69-
});
70-
71-
/// <inheritdoc />
72-
public virtual void Add(T item)
73-
=> Sync!.Modifying(() => AssertIsAlive(), () =>
74-
{
75-
AddInternal(item);
76-
return true;
77-
});
78-
79-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
80-
protected virtual void AddInternal(T item)
81-
=> _source.Add(item);
82-
8344
public void Add(T item, T item2, params T[] items)
8445
=> Sync!.Modifying(() => AssertIsAlive(), () =>
8546
{
@@ -89,68 +50,12 @@ public void Add(T item, T item2, params T[] items)
8950
AddInternal(i);
9051
return true;
9152
});
92-
public void AddRange(IEnumerable<T> items)
93-
{
94-
if (items is null) return;
95-
IReadOnlyList<T> enumerable = items switch
96-
{
97-
IImmutableList<T> i => i,
98-
T[] a => a,
99-
_ => items.ToArray(),
100-
101-
};
102-
103-
if (enumerable.Count == 0)
104-
return;
105-
106-
Sync!.Modifying(() => AssertIsAlive(), () =>
107-
{
108-
foreach (var item in enumerable)
109-
AddInternal(item);
110-
return true;
111-
});
112-
}
113-
114-
/// <inheritdoc />
115-
public void Clear()
116-
=> Sync!.Modifying(
117-
() => AssertIsAlive() && _source.Count != 0,
118-
() =>
119-
{
120-
int count = Count;
121-
bool hasItems = count != 0;
122-
if (hasItems)
123-
{
124-
_source.Clear();
125-
}
126-
return hasItems;
127-
});
128-
129-
/// <inheritdoc />
130-
public bool Contains(T item)
131-
=> Sync!.Reading(() => AssertIsAlive() && _source.Contains(item));
132-
133-
/// <inheritdoc />
134-
public void CopyTo(T[] array, int arrayIndex)
135-
=> Sync!.Reading(() =>
136-
{
137-
AssertIsAlive();
138-
_source.CopyTo(array, arrayIndex);
139-
});
140-
141-
/// <inheritdoc />
142-
public IEnumerator<T> GetEnumerator()
143-
=> Sync!.Reading(() =>
144-
{
145-
AssertIsAlive();
146-
return _source.GetEnumerator();
147-
});
14853

14954
/// <inheritdoc />
15055
public int IndexOf(T item)
15156
=> Sync!.Reading(
15257
() => AssertIsAlive()
153-
? _source.IndexOf(item)
58+
? InternalSource.IndexOf(item)
15459
: -1);
15560

15661
/// <inheritdoc />
@@ -159,20 +64,20 @@ public void Insert(int index, T item)
15964
() => AssertIsAlive(),
16065
() =>
16166
{
162-
_source.Insert(index, item);
67+
InternalSource.Insert(index, item);
16368
return true;
16469
});
16570

16671
/// <inheritdoc />
167-
public bool Remove(T item)
72+
public override bool Remove(T item)
16873
{
16974
int i = -1;
17075
return Sync!.Modifying(
17176
() => AssertIsAlive()
172-
&& (i = _source.IndexOf(item)) != -1,
77+
&& (i = InternalSource.IndexOf(item)) != -1,
17378
() =>
17479
{
175-
_source.RemoveAt(i);
80+
InternalSource.RemoveAt(i);
17681
return true;
17782
});
17883
}
@@ -183,17 +88,10 @@ public void RemoveAt(int index)
18388
() => AssertIsAlive(),
18489
() =>
18590
{
186-
_source.RemoveAt(index);
91+
InternalSource.RemoveAt(index);
18792
return true;
18893
});
18994

190-
IEnumerator IEnumerable.GetEnumerator()
191-
=> Sync!.Reading(() =>
192-
{
193-
AssertIsAlive();
194-
return _source.GetEnumerator();
195-
});
196-
19795
/// <summary>
19896
/// Synchonizes finding an item (<paramref name="target"/>), and if found, replaces it with the <paramref name="replacement"/>.
19997
/// </summary>
@@ -207,7 +105,7 @@ public bool Replace(T target, T replacement, bool throwIfNotFound = false)
207105
() =>
208106
{
209107
AssertIsAlive();
210-
index = _source.IndexOf(target);
108+
index = InternalSource.IndexOf(target);
211109
return index != -1 || (throwIfNotFound ? throw new ArgumentException("Not found.", nameof(target)) : false);
212110
},
213111
() =>

0 commit comments

Comments
 (0)