Skip to content

Commit

Permalink
Add multi-threaded collections (#692)
Browse files Browse the repository at this point in the history
  • Loading branch information
dunhor authored Jul 28, 2020
1 parent f6932fe commit ab89b9f
Show file tree
Hide file tree
Showing 10 changed files with 1,254 additions and 61 deletions.
212 changes: 183 additions & 29 deletions strings/base_collections_base.h

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions strings/base_collections_input_map.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@

namespace winrt::impl
{
template <typename K, typename V, typename Container>
struct input_map :
implements<input_map<K, V, Container>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
map_base<input_map<K, V, Container>, K, V>
template <typename K, typename V, typename Container, typename ThreadingBase>
struct map_impl :
implements<map_impl<K, V, Container, ThreadingBase>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
map_base<map_impl<K, V, Container, ThreadingBase>, K, V>,
ThreadingBase
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");

explicit input_map(Container&& values) : m_values(std::forward<Container>(values))
explicit map_impl(Container&& values) : m_values(std::forward<Container>(values))
{
}

Expand All @@ -22,11 +23,17 @@ namespace winrt::impl
return m_values;
}

using ThreadingBase::acquire_shared;
using ThreadingBase::acquire_exclusive;

private:

Container m_values;
};

template <typename K, typename V, typename Container>
using input_map = map_impl<K, V, Container, single_threaded_collection_base>;

template <typename K, typename V, typename Container>
auto make_input_map(Container&& values)
{
Expand Down
17 changes: 12 additions & 5 deletions strings/base_collections_input_vector.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@

namespace winrt::impl
{
template <typename T, typename Container>
struct input_vector :
implements<input_vector<T, Container>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>>,
vector_base<input_vector<T, Container>, T>
template <typename T, typename Container, typename ThreadingBase>
struct vector_impl :
implements<vector_impl<T, Container, ThreadingBase>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>>,
vector_base<vector_impl<T, Container, ThreadingBase>, T>,
ThreadingBase
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");

explicit input_vector(Container&& values) : m_values(std::forward<Container>(values))
explicit vector_impl(Container&& values) : m_values(std::forward<Container>(values))
{
}

Expand All @@ -22,10 +23,16 @@ namespace winrt::impl
return m_values;
}

using ThreadingBase::acquire_shared;
using ThreadingBase::acquire_exclusive;

private:

Container m_values;
};

template <typename T, typename Container>
using input_vector = vector_impl<T, Container, single_threaded_collection_base>;
}

WINRT_EXPORT namespace winrt::param
Expand Down
57 changes: 53 additions & 4 deletions strings/base_collections_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
namespace winrt::impl
{
template <typename K, typename V, typename Container>
struct observable_map :
implements<observable_map<K, V, Container>, wfc::IObservableMap<K, V>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
observable_map_base<observable_map<K, V, Container>, K, V>
using multi_threaded_map = map_impl<K, V, Container, multi_threaded_collection_base>;

template <typename K, typename V, typename Container, typename ThreadingBase>
struct observable_map_impl :
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>>>,
observable_map_base<observable_map_impl<K, V, Container, ThreadingBase>, K, V>,
ThreadingBase
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");

explicit observable_map(Container&& values) : m_values(std::forward<Container>(values))
explicit observable_map_impl(Container&& values) : m_values(std::forward<Container>(values))
{
}

Expand All @@ -22,10 +26,19 @@ namespace winrt::impl
return m_values;
}

using ThreadingBase::acquire_shared;
using ThreadingBase::acquire_exclusive;

private:

Container m_values;
};

template <typename K, typename V, typename Container>
using observable_map = observable_map_impl<K, V, Container, single_threaded_collection_base>;

template <typename K, typename V, typename Container>
using multi_threaded_observable_map = observable_map_impl<K, V, Container, multi_threaded_collection_base>;
}

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

template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map()
{
return make<impl::multi_threaded_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
}

template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map(std::map<K, V, Compare, Allocator>&& values)
{
return make<impl::multi_threaded_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
}

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>>>
Windows::Foundation::Collections::IMap<K, V> multi_threaded_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
{
return make<impl::multi_threaded_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
}

template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> single_threaded_observable_map()
{
Expand All @@ -65,6 +96,24 @@ WINRT_EXPORT namespace winrt
{
return make<impl::observable_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
}

template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map()
{
return make<impl::multi_threaded_observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
}

template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map(std::map<K, V, Compare, Allocator>&& values)
{
return make<impl::multi_threaded_observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
}

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>>>
Windows::Foundation::Collections::IObservableMap<K, V> multi_threaded_observable_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
{
return make<impl::multi_threaded_observable_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
}
}

namespace std
Expand Down
77 changes: 59 additions & 18 deletions strings/base_collections_vector.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@

namespace winrt::impl
{
template <typename Container>
template <typename T, typename Container>
using multi_threaded_vector = vector_impl<T, Container, multi_threaded_collection_base>;

template <typename Container, typename ThreadingBase = single_threaded_collection_base>
struct inspectable_observable_vector :
observable_vector_base<inspectable_observable_vector<Container>, Windows::Foundation::IInspectable>,
implements<inspectable_observable_vector<Container>,
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
observable_vector_base<inspectable_observable_vector<Container, ThreadingBase>, Windows::Foundation::IInspectable>,
implements<inspectable_observable_vector<Container, ThreadingBase>,
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>,
ThreadingBase
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");

Expand All @@ -23,23 +27,30 @@ namespace winrt::impl
return m_values;
}

using ThreadingBase::acquire_shared;
using ThreadingBase::acquire_exclusive;

private:

Container m_values;
};

template <typename T, typename Container>
template <typename Container>
using multi_threaded_inspectable_observable_vector = inspectable_observable_vector<Container, multi_threaded_collection_base>;

template <typename T, typename Container, typename ThreadingBase = single_threaded_collection_base>
struct convertible_observable_vector :
observable_vector_base<convertible_observable_vector<T, Container>, T>,
implements<convertible_observable_vector<T, Container>,
observable_vector_base<convertible_observable_vector<T, Container, ThreadingBase>, T>,
implements<convertible_observable_vector<T, Container, ThreadingBase>,
wfc::IObservableVector<T>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>,
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>,
ThreadingBase
{
static_assert(!std::is_same_v<T, Windows::Foundation::IInspectable>);
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");

using container_type = convertible_observable_vector<T, Container>;
using base_type = observable_vector_base<convertible_observable_vector<T, Container>, T>;
using container_type = convertible_observable_vector<T, Container, ThreadingBase>;
using base_type = observable_vector_base<convertible_observable_vector<T, Container, ThreadingBase>, T>;

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

using ThreadingBase::acquire_shared;
using ThreadingBase::acquire_exclusive;

auto First()
{
struct result
Expand All @@ -68,6 +82,7 @@ namespace winrt::impl

operator wfc::IIterator<Windows::Foundation::IInspectable>()
{
auto guard = container->acquire_shared();
return make<iterator>(container);
}
};
Expand Down Expand Up @@ -115,6 +130,7 @@ namespace winrt::impl

uint32_t GetMany(uint32_t const startIndex, array_view<Windows::Foundation::IInspectable> values) const
{
auto guard = this->acquire_shared();
if (startIndex >= m_values.size())
{
return 0;
Expand Down Expand Up @@ -202,11 +218,6 @@ namespace winrt::impl
impl::collection_version::iterator_type,
implements<iterator, Windows::Foundation::Collections::IIterator<Windows::Foundation::IInspectable>>
{
void abi_enter()
{
check_version(*m_owner);
}

explicit iterator(container_type* const container) noexcept :
impl::collection_version::iterator_type(*container),
m_current(container->get_container().begin()),
Expand All @@ -217,6 +228,8 @@ namespace winrt::impl

Windows::Foundation::IInspectable Current() const
{
auto guard = m_owner->acquire_shared();
check_version(*m_owner);
if (m_current == m_end)
{
throw hresult_out_of_bounds();
Expand All @@ -225,23 +238,29 @@ namespace winrt::impl
return box_value(*m_current);
}

bool HasCurrent() const noexcept
bool HasCurrent() const
{
auto guard = m_owner->acquire_shared();
check_version(*m_owner);
return m_current != m_end;
}

bool MoveNext() noexcept
bool MoveNext()
{
auto guard = m_owner->acquire_exclusive();
check_version(*m_owner);
if (m_current != m_end)
{
++m_current;
}

return HasCurrent();
return m_current != m_end;
}

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

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

Container m_values;
};

template <typename T, typename Container>
using multi_threaded_convertible_observable_vector = convertible_observable_vector<T, Container, multi_threaded_collection_base>;
}

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

template <typename T, typename Allocator = std::allocator<T>>
Windows::Foundation::Collections::IVector<T> multi_threaded_vector(std::vector<T, Allocator>&& values = {})
{
return make<impl::multi_threaded_vector<T, std::vector<T, Allocator>>>(std::move(values));
}

template <typename T, typename Allocator = std::allocator<T>>
Windows::Foundation::Collections::IObservableVector<T> single_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
{
Expand All @@ -284,4 +312,17 @@ WINRT_EXPORT namespace winrt
return make<impl::convertible_observable_vector<T, std::vector<T, Allocator>>>(std::move(values));
}
}

template <typename T, typename Allocator = std::allocator<T>>
Windows::Foundation::Collections::IObservableVector<T> multi_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
{
if constexpr (std::is_same_v<T, Windows::Foundation::IInspectable>)
{
return make<impl::multi_threaded_inspectable_observable_vector<std::vector<T, Allocator>>>(std::move(values));
}
else
{
return make<impl::multi_threaded_convertible_observable_vector<T, std::vector<T, Allocator>>>(std::move(values));
}
}
}
21 changes: 21 additions & 0 deletions strings/base_lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ WINRT_EXPORT namespace winrt
m_mutex.lock();
}

slim_lock_guard(slim_lock_guard const&) = delete;

~slim_lock_guard() noexcept
{
m_mutex.unlock();
Expand All @@ -67,6 +69,25 @@ WINRT_EXPORT namespace winrt
slim_mutex& m_mutex;
};

struct slim_shared_lock_guard
{
explicit slim_shared_lock_guard(slim_mutex& m) noexcept :
m_mutex(m)
{
m_mutex.lock_shared();
}

slim_shared_lock_guard(slim_shared_lock_guard const&) = delete;

~slim_shared_lock_guard() noexcept
{
m_mutex.unlock_shared();
}

private:
slim_mutex& m_mutex;
};

struct slim_condition_variable
{
slim_condition_variable(slim_condition_variable const&) = delete;
Expand Down
Loading

0 comments on commit ab89b9f

Please sign in to comment.