Created
November 19, 2023 07:15
-
-
Save jonwis/1354089c149f30e609d91e4156b5641e to your computer and use it in GitHub Desktop.
Yet another enum iterator attempt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <wil/com.h> | |
// Wraps a type like IEnumIUknown and exposes it as a forward iterator, | |
// or like IEnumIDList and exposes it as a forward iterator of type TStoredType. | |
// The IEnumType must have the following methods: | |
// HRESULT Next(ULONG celt, T* rgelt, ULONG* pceltFetched) | |
template <typename IEnumType, typename TStoredType> | |
struct iterator | |
{ | |
wil::com_ptr<IEnumType> m_enum{}; | |
uint32_t m_offset{0}; | |
bool m_isEnd{false}; | |
TStoredType m_currentValue{}; | |
struct end_tag_t{ }; | |
iterator(iterator&&) = default; | |
iterator(iterator const&) = delete; | |
iterator& operator=(iterator&&) = default; | |
iterator& operator=(iterator const&) = delete; | |
iterator(IEnumType* enumPtr) : m_enum(enumPtr) | |
{ | |
FetchNext(); | |
} | |
explicit iterator(end_tag_t) : m_isEnd(true) | |
{ | |
} | |
auto operator->() | |
{ | |
return wistd::addressof(m_currentValue); | |
} | |
auto& operator*() | |
{ | |
return m_currentValue; | |
} | |
iterator& operator++() | |
{ | |
// If we're already at the end, don't try to advance. Otherwise, use Next to advance. | |
if (!m_isEnd) | |
{ | |
FetchNext(); | |
} | |
return *this; | |
} | |
bool operator!=(iterator const& other) const | |
{ | |
return !(*this == other); | |
} | |
bool operator==(iterator const& other) const | |
{ | |
return (m_isEnd == other.m_isEnd) || | |
(m_enum == other.m_enum && m_offset == other.m_offset); | |
} | |
private: | |
void FetchNext() | |
{ | |
if (!m_isEnd) | |
{ | |
m_currentValue = {}; | |
auto hr = m_enum->Next(1, &m_currentValue, nullptr); | |
if (hr == S_FALSE) | |
{ | |
m_isEnd = true; | |
} | |
else if (FAILED(hr)) | |
{ | |
throw winrt::hresult_error(hr, L"Failed to get next"); | |
} | |
else | |
{ | |
++m_offset; | |
} | |
} | |
} | |
}; | |
auto make_range(IEnumUnknown* enumPtr) | |
{ | |
using i = iterator<IEnumUnknown, wil::com_ptr<::IUnknown>>; | |
return std::make_pair<i, i>(enumPtr, i{i::end_tag_t{}}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is kind of what I had in the original PR: microsoft/wil#234
the problem is that we need a bit more traits for the output type for Next: e.g. PIDLs aren't COM, but should be wrapped in something like a wil::unique_cotaskmemptr to not be leaked. So perhaps something with a traits that can be specialized would work?
Or maybe I'm overthinking and this can be
thoughts?