Skip to content

Commit ab89b9f

Browse files
authored
Add multi-threaded collections (#692)
1 parent f6932fe commit ab89b9f

10 files changed

+1254
-61
lines changed

strings/base_collections_base.h

Lines changed: 183 additions & 29 deletions
Large diffs are not rendered by default.

strings/base_collections_input_map.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11

22
namespace winrt::impl
33
{
4-
template <typename K, typename V, typename Container>
5-
struct input_map :
6-
implements<input_map<K, V, Container>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
7-
map_base<input_map<K, V, Container>, K, V>
4+
template <typename K, typename V, typename Container, typename ThreadingBase>
5+
struct map_impl :
6+
implements<map_impl<K, V, Container, ThreadingBase>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
7+
map_base<map_impl<K, V, Container, ThreadingBase>, K, V>,
8+
ThreadingBase
89
{
910
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
1011

11-
explicit input_map(Container&& values) : m_values(std::forward<Container>(values))
12+
explicit map_impl(Container&& values) : m_values(std::forward<Container>(values))
1213
{
1314
}
1415

@@ -22,11 +23,17 @@ namespace winrt::impl
2223
return m_values;
2324
}
2425

26+
using ThreadingBase::acquire_shared;
27+
using ThreadingBase::acquire_exclusive;
28+
2529
private:
2630

2731
Container m_values;
2832
};
2933

34+
template <typename K, typename V, typename Container>
35+
using input_map = map_impl<K, V, Container, single_threaded_collection_base>;
36+
3037
template <typename K, typename V, typename Container>
3138
auto make_input_map(Container&& values)
3239
{

strings/base_collections_input_vector.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11

22
namespace winrt::impl
33
{
4-
template <typename T, typename Container>
5-
struct input_vector :
6-
implements<input_vector<T, Container>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>>,
7-
vector_base<input_vector<T, Container>, T>
4+
template <typename T, typename Container, typename ThreadingBase>
5+
struct vector_impl :
6+
implements<vector_impl<T, Container, ThreadingBase>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>>,
7+
vector_base<vector_impl<T, Container, ThreadingBase>, T>,
8+
ThreadingBase
89
{
910
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
1011

11-
explicit input_vector(Container&& values) : m_values(std::forward<Container>(values))
12+
explicit vector_impl(Container&& values) : m_values(std::forward<Container>(values))
1213
{
1314
}
1415

@@ -22,10 +23,16 @@ namespace winrt::impl
2223
return m_values;
2324
}
2425

26+
using ThreadingBase::acquire_shared;
27+
using ThreadingBase::acquire_exclusive;
28+
2529
private:
2630

2731
Container m_values;
2832
};
33+
34+
template <typename T, typename Container>
35+
using input_vector = vector_impl<T, Container, single_threaded_collection_base>;
2936
}
3037

3138
WINRT_EXPORT namespace winrt::param

strings/base_collections_map.h

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
namespace winrt::impl
33
{
44
template <typename K, typename V, typename Container>
5-
struct observable_map :
6-
implements<observable_map<K, V, Container>, wfc::IObservableMap<K, V>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
7-
observable_map_base<observable_map<K, V, Container>, K, V>
5+
using multi_threaded_map = map_impl<K, V, Container, multi_threaded_collection_base>;
6+
7+
template <typename K, typename V, typename Container, typename ThreadingBase>
8+
struct observable_map_impl :
9+
implements<observable_map_impl<K, V, Container, ThreadingBase>, wfc::IObservableMap<K, V>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
10+
observable_map_base<observable_map_impl<K, V, Container, ThreadingBase>, K, V>,
11+
ThreadingBase
812
{
913
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
1014

11-
explicit observable_map(Container&& values) : m_values(std::forward<Container>(values))
15+
explicit observable_map_impl(Container&& values) : m_values(std::forward<Container>(values))
1216
{
1317
}
1418

@@ -22,10 +26,19 @@ namespace winrt::impl
2226
return m_values;
2327
}
2428

29+
using ThreadingBase::acquire_shared;
30+
using ThreadingBase::acquire_exclusive;
31+
2532
private:
2633

2734
Container m_values;
2835
};
36+
37+
template <typename K, typename V, typename Container>
38+
using observable_map = observable_map_impl<K, V, Container, single_threaded_collection_base>;
39+
40+
template <typename K, typename V, typename Container>
41+
using multi_threaded_observable_map = observable_map_impl<K, V, Container, multi_threaded_collection_base>;
2942
}
3043

3144
WINRT_EXPORT namespace winrt
@@ -48,6 +61,24 @@ WINRT_EXPORT namespace winrt
4861
return make<impl::input_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
4962
}
5063

64+
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
65+
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map()
66+
{
67+
return make<impl::multi_threaded_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
68+
}
69+
70+
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
71+
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map(std::map<K, V, Compare, Allocator>&& values)
72+
{
73+
return make<impl::multi_threaded_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
74+
}
75+
76+
template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
77+
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
78+
{
79+
return make<impl::multi_threaded_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
80+
}
81+
5182
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
5283
Windows::Foundation::Collections::IObservableMap<K, V> single_threaded_observable_map()
5384
{
@@ -65,6 +96,24 @@ WINRT_EXPORT namespace winrt
6596
{
6697
return make<impl::observable_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
6798
}
99+
100+
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
101+
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map()
102+
{
103+
return make<impl::multi_threaded_observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
104+
}
105+
106+
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
107+
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map(std::map<K, V, Compare, Allocator>&& values)
108+
{
109+
return make<impl::multi_threaded_observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
110+
}
111+
112+
template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
113+
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
114+
{
115+
return make<impl::multi_threaded_observable_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
116+
}
68117
}
69118

70119
namespace std

strings/base_collections_vector.h

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11

22
namespace winrt::impl
33
{
4-
template <typename Container>
4+
template <typename T, typename Container>
5+
using multi_threaded_vector = vector_impl<T, Container, multi_threaded_collection_base>;
6+
7+
template <typename Container, typename ThreadingBase = single_threaded_collection_base>
58
struct inspectable_observable_vector :
6-
observable_vector_base<inspectable_observable_vector<Container>, Windows::Foundation::IInspectable>,
7-
implements<inspectable_observable_vector<Container>,
8-
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
9+
observable_vector_base<inspectable_observable_vector<Container, ThreadingBase>, Windows::Foundation::IInspectable>,
10+
implements<inspectable_observable_vector<Container, ThreadingBase>,
11+
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>,
12+
ThreadingBase
913
{
1014
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
1115

@@ -23,23 +27,30 @@ namespace winrt::impl
2327
return m_values;
2428
}
2529

30+
using ThreadingBase::acquire_shared;
31+
using ThreadingBase::acquire_exclusive;
32+
2633
private:
2734

2835
Container m_values;
2936
};
3037

31-
template <typename T, typename Container>
38+
template <typename Container>
39+
using multi_threaded_inspectable_observable_vector = inspectable_observable_vector<Container, multi_threaded_collection_base>;
40+
41+
template <typename T, typename Container, typename ThreadingBase = single_threaded_collection_base>
3242
struct convertible_observable_vector :
33-
observable_vector_base<convertible_observable_vector<T, Container>, T>,
34-
implements<convertible_observable_vector<T, Container>,
43+
observable_vector_base<convertible_observable_vector<T, Container, ThreadingBase>, T>,
44+
implements<convertible_observable_vector<T, Container, ThreadingBase>,
3545
wfc::IObservableVector<T>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>,
36-
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
46+
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>,
47+
ThreadingBase
3748
{
3849
static_assert(!std::is_same_v<T, Windows::Foundation::IInspectable>);
3950
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
4051

41-
using container_type = convertible_observable_vector<T, Container>;
42-
using base_type = observable_vector_base<convertible_observable_vector<T, Container>, T>;
52+
using container_type = convertible_observable_vector<T, Container, ThreadingBase>;
53+
using base_type = observable_vector_base<convertible_observable_vector<T, Container, ThreadingBase>, T>;
4354

4455
explicit convertible_observable_vector(Container&& values) : m_values(std::forward<Container>(values))
4556
{
@@ -55,6 +66,9 @@ namespace winrt::impl
5566
return m_values;
5667
}
5768

69+
using ThreadingBase::acquire_shared;
70+
using ThreadingBase::acquire_exclusive;
71+
5872
auto First()
5973
{
6074
struct result
@@ -68,6 +82,7 @@ namespace winrt::impl
6882

6983
operator wfc::IIterator<Windows::Foundation::IInspectable>()
7084
{
85+
auto guard = container->acquire_shared();
7186
return make<iterator>(container);
7287
}
7388
};
@@ -115,6 +130,7 @@ namespace winrt::impl
115130

116131
uint32_t GetMany(uint32_t const startIndex, array_view<Windows::Foundation::IInspectable> values) const
117132
{
133+
auto guard = this->acquire_shared();
118134
if (startIndex >= m_values.size())
119135
{
120136
return 0;
@@ -202,11 +218,6 @@ namespace winrt::impl
202218
impl::collection_version::iterator_type,
203219
implements<iterator, Windows::Foundation::Collections::IIterator<Windows::Foundation::IInspectable>>
204220
{
205-
void abi_enter()
206-
{
207-
check_version(*m_owner);
208-
}
209-
210221
explicit iterator(container_type* const container) noexcept :
211222
impl::collection_version::iterator_type(*container),
212223
m_current(container->get_container().begin()),
@@ -217,6 +228,8 @@ namespace winrt::impl
217228

218229
Windows::Foundation::IInspectable Current() const
219230
{
231+
auto guard = m_owner->acquire_shared();
232+
check_version(*m_owner);
220233
if (m_current == m_end)
221234
{
222235
throw hresult_out_of_bounds();
@@ -225,23 +238,29 @@ namespace winrt::impl
225238
return box_value(*m_current);
226239
}
227240

228-
bool HasCurrent() const noexcept
241+
bool HasCurrent() const
229242
{
243+
auto guard = m_owner->acquire_shared();
244+
check_version(*m_owner);
230245
return m_current != m_end;
231246
}
232247

233-
bool MoveNext() noexcept
248+
bool MoveNext()
234249
{
250+
auto guard = m_owner->acquire_exclusive();
251+
check_version(*m_owner);
235252
if (m_current != m_end)
236253
{
237254
++m_current;
238255
}
239256

240-
return HasCurrent();
257+
return m_current != m_end;
241258
}
242259

243260
uint32_t GetMany(array_view<Windows::Foundation::IInspectable> values)
244261
{
262+
auto guard = m_owner->acquire_exclusive();
263+
check_version(*m_owner);
245264
uint32_t const actual = (std::min)(static_cast<uint32_t>(std::distance(m_current, m_end)), values.size());
246265

247266
std::transform(m_current, m_current + actual, values.begin(), [&](auto && value)
@@ -262,6 +281,9 @@ namespace winrt::impl
262281

263282
Container m_values;
264283
};
284+
285+
template <typename T, typename Container>
286+
using multi_threaded_convertible_observable_vector = convertible_observable_vector<T, Container, multi_threaded_collection_base>;
265287
}
266288

267289
WINRT_EXPORT namespace winrt
@@ -272,6 +294,12 @@ WINRT_EXPORT namespace winrt
272294
return make<impl::input_vector<T, std::vector<T, Allocator>>>(std::move(values));
273295
}
274296

297+
template <typename T, typename Allocator = std::allocator<T>>
298+
Windows::Foundation::Collections::IVector<T> multi_threaded_vector(std::vector<T, Allocator>&& values = {})
299+
{
300+
return make<impl::multi_threaded_vector<T, std::vector<T, Allocator>>>(std::move(values));
301+
}
302+
275303
template <typename T, typename Allocator = std::allocator<T>>
276304
Windows::Foundation::Collections::IObservableVector<T> single_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
277305
{
@@ -284,4 +312,17 @@ WINRT_EXPORT namespace winrt
284312
return make<impl::convertible_observable_vector<T, std::vector<T, Allocator>>>(std::move(values));
285313
}
286314
}
315+
316+
template <typename T, typename Allocator = std::allocator<T>>
317+
Windows::Foundation::Collections::IObservableVector<T> multi_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
318+
{
319+
if constexpr (std::is_same_v<T, Windows::Foundation::IInspectable>)
320+
{
321+
return make<impl::multi_threaded_inspectable_observable_vector<std::vector<T, Allocator>>>(std::move(values));
322+
}
323+
else
324+
{
325+
return make<impl::multi_threaded_convertible_observable_vector<T, std::vector<T, Allocator>>>(std::move(values));
326+
}
327+
}
287328
}

strings/base_lock.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ WINRT_EXPORT namespace winrt
5858
m_mutex.lock();
5959
}
6060

61+
slim_lock_guard(slim_lock_guard const&) = delete;
62+
6163
~slim_lock_guard() noexcept
6264
{
6365
m_mutex.unlock();
@@ -67,6 +69,25 @@ WINRT_EXPORT namespace winrt
6769
slim_mutex& m_mutex;
6870
};
6971

72+
struct slim_shared_lock_guard
73+
{
74+
explicit slim_shared_lock_guard(slim_mutex& m) noexcept :
75+
m_mutex(m)
76+
{
77+
m_mutex.lock_shared();
78+
}
79+
80+
slim_shared_lock_guard(slim_shared_lock_guard const&) = delete;
81+
82+
~slim_shared_lock_guard() noexcept
83+
{
84+
m_mutex.unlock_shared();
85+
}
86+
87+
private:
88+
slim_mutex& m_mutex;
89+
};
90+
7091
struct slim_condition_variable
7192
{
7293
slim_condition_variable(slim_condition_variable const&) = delete;

0 commit comments

Comments
 (0)