Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions strings/base_collections_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,15 @@ namespace winrt::impl

bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const
{
return IndexOf(unbox_value<T>(value), index);
try
{
return IndexOf(unbox_value<T>(value), index);
}
catch (hresult_no_interface const&)
{
index = 0;
return false;
}
}

using base_type::GetMany;
Expand Down Expand Up @@ -167,16 +175,15 @@ namespace winrt::impl

void ReplaceAll(array_view<Windows::Foundation::IInspectable const> values)
{
this->increment_version();
m_values.clear();
m_values.reserve(values.size());
Container new_values;
new_values.reserve(values.size());

std::transform(values.begin(), values.end(), std::back_inserter(m_values), [&](auto && value)
std::transform(values.begin(), values.end(), std::back_inserter(new_values), [&](auto && value)
{
return unbox_value<T>(value);
});

this->call_changed(Windows::Foundation::Collections::CollectionChange::Reset, 0);
base_type::ReplaceAll(std::move(new_values));
}

using base_type::VectorChanged;
Expand Down
33 changes: 20 additions & 13 deletions strings/base_reference_produce.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,26 +288,33 @@ WINRT_EXPORT namespace winrt
{
return value.as<T>();
}
else if constexpr (std::is_enum_v<T>)
else
{
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
if (!value)
{
return temp.Value();
throw hresult_no_interface();
}
else
if constexpr (std::is_enum_v<T>)
{
return static_cast<T>(value.as<Windows::Foundation::IReference<std::underlying_type_t<T>>>().Value());
if (auto temp = value.try_as<Windows::Foundation::IReference<T>>())
{
return temp.Value();
}
else
{
return static_cast<T>(value.as<Windows::Foundation::IReference<std::underlying_type_t<T>>>().Value());
}
}
}
#ifdef WINRT_IMPL_IUNKNOWN_DEFINED
else if constexpr (std::is_same_v<T, GUID>)
{
return value.as<Windows::Foundation::IReference<guid>>().Value();
}
else if constexpr (std::is_same_v<T, GUID>)
{
return value.as<Windows::Foundation::IReference<guid>>().Value();
}
#endif
else
{
return value.as<Windows::Foundation::IReference<T>>().Value();
else
{
return value.as<Windows::Foundation::IReference<T>>().Value();
}
}
}

Expand Down
68 changes: 64 additions & 4 deletions test/test/single_threaded_observable_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ TEST_CASE("single_threaded_observable_vector")
REQUIRE((vector_i.IndexOf(2, index) && index == 1));
index = 0;
REQUIRE((vector_o.IndexOf(box_value(2), index) && index == 1));

// A vector of integers never contains non-integers.
REQUIRE(!vector_o.IndexOf(nullptr, index));
REQUIRE(!vector_o.IndexOf(box_value(L"Not-an-integer"), index));
}
{
// GetView forwarding.
Expand All @@ -241,6 +245,10 @@ TEST_CASE("single_threaded_observable_vector")

REQUIRE(vector_i.GetAt(0) == 10);
REQUIRE(vector_i.GetAt(1) == 20);

// Can't put non-integers in a vector of integers.
REQUIRE_THROWS_AS(vector_o.SetAt(0, nullptr), hresult_no_interface);
REQUIRE_THROWS_AS(vector_o.SetAt(0, box_value(L"Not-an-integer")), hresult_no_interface);
}
{
// InsertAt forwarding.
Expand All @@ -258,6 +266,10 @@ TEST_CASE("single_threaded_observable_vector")
REQUIRE(vector_i.GetAt(1) == 2);
REQUIRE(vector_i.GetAt(2) == 3);
REQUIRE(vector_i.GetAt(3) == 4);

// Can't put non-integers in a vector of integers.
REQUIRE_THROWS_AS(vector_o.InsertAt(0, nullptr), hresult_no_interface);
REQUIRE_THROWS_AS(vector_o.InsertAt(0, box_value(L"Not-an-integer")), hresult_no_interface);
}
{
// Append forwarding.
Expand All @@ -273,6 +285,10 @@ TEST_CASE("single_threaded_observable_vector")
REQUIRE(vector_i.Size() == 2);
REQUIRE(vector_i.GetAt(0) == 1);
REQUIRE(vector_i.GetAt(1) == 2);

// Can't put non-integers in a vector of integers.
REQUIRE_THROWS_AS(vector_o.Append(nullptr), hresult_no_interface);
REQUIRE_THROWS_AS(vector_o.Append(box_value(L"Not-an-integer")), hresult_no_interface);
}
{
// GetMany boxing.
Expand Down Expand Up @@ -334,13 +350,13 @@ TEST_CASE("single_threaded_observable_vector")
bool changed_i{};
bool changed_o{};

vector_i.VectorChanged([&](IObservableVector<int> const& sender, IVectorChangedEventArgs const&)
auto token_i = vector_i.VectorChanged(auto_revoke, [&](IObservableVector<int> const& sender, IVectorChangedEventArgs const&)
{
changed_i = sender.GetAt(0) == 123;
REQUIRE(sender == vector_i);
});

vector_o.VectorChanged([&](IObservableVector<IInspectable> const& sender, IVectorChangedEventArgs const&)
auto token_o = vector_o.VectorChanged(auto_revoke, [&](IObservableVector<IInspectable> const& sender, IVectorChangedEventArgs const&)
{
changed_o = unbox_value<int>(sender.GetAt(0)) == 123;
REQUIRE(sender == vector_o);
Expand All @@ -357,6 +373,35 @@ TEST_CASE("single_threaded_observable_vector")
REQUIRE(vector_i.Size() == 1);
REQUIRE(vector_i.GetAt(0) == 123);
}
{
bool changed_i{};
bool changed_o{};

auto token_i = vector_i.VectorChanged(auto_revoke, [&](IObservableVector<int> const& sender, IVectorChangedEventArgs const&)
{
changed_i = true;
REQUIRE(sender == vector_i);
});

auto token_o = vector_o.VectorChanged(auto_revoke, [&](IObservableVector<IInspectable> const& sender, IVectorChangedEventArgs const&)
{
changed_i = true;
REQUIRE(sender == vector_o);
});

// Verify strong exception guarantee when replacing with non-integers.
REQUIRE_THROWS_AS(vector_o.ReplaceAll({ box_value(42), nullptr }), hresult_no_interface);
REQUIRE(!changed_i); // unchanged on failure
REQUIRE(!changed_o);
REQUIRE(vector_i.Size() == 1);
REQUIRE(vector_i.GetAt(0) == 123);

REQUIRE_THROWS_AS(vector_o.ReplaceAll({ box_value(L"Not-an-integer") }), hresult_no_interface);
REQUIRE(!changed_i); // unchanged on failure
REQUIRE(!changed_o);
REQUIRE(vector_i.Size() == 1);
REQUIRE(vector_i.GetAt(0) == 123);
}

{
IIterator<int> iterator_i = vector_i.First();
Expand All @@ -368,13 +413,13 @@ TEST_CASE("single_threaded_observable_vector")
bool changed_i{};
bool changed_o{};

vector_i.VectorChanged([&](IObservableVector<int> const& sender, IVectorChangedEventArgs const&)
auto token_i = vector_i.VectorChanged(auto_revoke, [&](IObservableVector<int> const& sender, IVectorChangedEventArgs const&)
{
changed_i = sender.GetAt(0) == 123;
REQUIRE(sender == vector_i);
});

vector_o.VectorChanged([&](IObservableVector<IInspectable> const& sender, IVectorChangedEventArgs const&)
auto token_o = vector_o.VectorChanged(auto_revoke, [&](IObservableVector<IInspectable> const& sender, IVectorChangedEventArgs const&)
{
changed_o = unbox_value<int>(sender.GetAt(0)) == 123;
REQUIRE(sender == vector_o);
Expand All @@ -392,4 +437,19 @@ TEST_CASE("single_threaded_observable_vector")
REQUIRE(vector_i.GetAt(0) == 123);
}
}

{
IObservableVector<IVector<int>> vector_i = single_threaded_observable_vector<IVector<int>>({ });
IObservableVector<IInspectable> vector_o = vector_i.as<IObservableVector<IInspectable>>();

// Verify that nulls are legal if the underlying type derives from IInspectable.
REQUIRE_NOTHROW(vector_o.Append(nullptr));
uint32_t index = 99;
REQUIRE(vector_o.IndexOf(nullptr, index));
REQUIRE(index == 0);

// Verify that type mismatch should report "not found" rather than
// finding the null entry.
REQUIRE(!vector_o.IndexOf(box_value(L"not-a-vector"), index));
}
}