[Copilot] Add wil::batched_range and wil::already_complete / already_failed C++/WinRT helpers - #669
Open
Jon Wiswall (jonwis) wants to merge 8 commits into
Conversation
Implements the two helpers spun out of microsoft/cppwinrt#1608 into WIL: - make_ready() / make_ready(value) / make_failed(): already-settled IAsyncAction / IAsyncOperation<T> with no coroutine frame, firing Completed inline with a single-assignment guard (microsoft#663). - batched(collection): range-for adapter that prefetches elements in blocks via GetMany instead of one ABI crossing per element, for indexed (IVector/IVectorView) and iterable-only (IIterable/IIterator, including map IKeyValuePair) collections (microsoft#664). Both live in cppwinrt_helpers.h next to to_vector, reusing its is_winrt_vector_like / is_winrt_iterator_like detection and the re-includable per-header guard pattern. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Collapse batched_indexed_iterator and batched_buffered_iterator into a single input iterator parameterized on a small refill 'source' policy. As a range-for-only adapter it no longer needs Size(), the GetAt fallback, or random access: it block-prefetches via GetMany and stops when a block comes back short, exactly matching to_vector's exhaustion rule. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rename the public helper and its detail range struct (batched_range -> batched_view) to avoid a name clash. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cover exact block-boundary multiples (1/127/128/129/256/257) on both the indexed and iterable paths to exercise the full-block-then-empty-refill termination, ordering across seams, single element, and an IIterator advanced past its start yielding only the remainder. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The failed-operation path never reads m_result (GetResults throws first), but default-constructing it would activate a projected runtimeclass result -- or fail to compile for a class without a default constructor (e.g. Uri). Init the storage with a null handle for object types and a value-init otherwise. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Jon Wiswall (jonwis)
requested review from
Chris Guzak (ChrisGuzak) and
Raymond Chen (oldnewthing)
August 25, 2026 01:54
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Two C++/WinRT helpers in
wil/cppwinrt_helpers.h, spun out of the review discussion on microsoft/cppwinrt#1608 — C++/WinRT stays projection-only, so these interop conveniences live in WIL. Resolves #663 and #664.wil::already_complete/wil::already_failed(#663)Return an
IAsyncAction/IAsyncOperation<T>that is already settled, with no coroutine frame —co_await,.get(), and aCompletedhandler all complete synchronously.A single
winrt::implementsobject over the async interface +IAsyncInfo;Completedis fired inline with a single-assignment guard (throwshresult_illegal_delegate_assignmenton a second set), no mutex — the compact shape from Raymond Chen's "already-completed asynchronous activity" series. The result storage is null-initialized for projected object types so the faulted path never activates (or requires a default constructor for) a runtimeclass result.wil::batched_range(#664)A range-for adapter that prefetches elements in blocks via
GetManyinstead of one ABI round-trip per element. On a cross-process or heavily-marshaled collection the per-element crossings dominate, so batching cuts them to roughly one per block.Works for
IVector<T>,IVectorView<T>,IIterable<T>,IIterator<T>, and anything C++/WinRT projects those for (PropertySet,IMap<K,V>, …). Indexed collections prefetch withGetMany(index, …); iterable-only collections buffer throughIIterator::GetMany. It's a single-pass input range — a yielded element outlives the step that produced it, matching the observable behavior ofwil::to_vector. Block prefetch stops onceGetManyreturns a short block. Both shapes share one input iterator that differs only in how a block is refilled.Testing
New coverage in
tests/CppWinRTTests.cpp:already_complete/already_failedcompleted/faulted status,co_awaitand.get(), inlineCompletedfiring, double-assignment throwing, a runtimeclass (Uri) result on the faulted path, and non-trivial result round-trip;batched_rangeacross the indexed and iterable paths, map/IKeyValuePair, exact block-boundary multiples (1/127/128/129/256/257) for ordering and clean termination, empty collections, duck-typed non-WinRT shapes, and an iterator advanced past its start yielding only the remainder. Built clean across clang and MSVC (debug + relwithdebinfo); full[cppwinrt]suite passes.References
(via Copilot)