|
JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
|
Eager materialization adaptor — explicitly terminates a lazy range pipeline and realizes it into a concrete container C.
More...
#include <ranges>#include "jh/conceptual/collectable_container.h"#include "jh/ranges/to.h"#include "jh/metax/adl_apply.h"Go to the source code of this file.
Classes | |
| struct | jh::ranges::collect_fn< C > |
Function object implementing jh::ranges::collect. More... | |
Namespaces | |
| namespace | jh::ranges |
| Semantic pipeline namespace for JH range operations. | |
Functions | |
| template<typename C, std::ranges::range R> | |
| constexpr auto | jh::ranges::collect_adaptor (R &&r) |
Core implementation for jh::ranges::collect adaptor. | |
Variables | |
| template<typename C> | |
| constexpr collect_fn< C > | jh::ranges::collect {} |
Global instance of the collect adaptor. | |
Eager materialization adaptor — explicitly terminates a lazy range pipeline and realizes it into a concrete container C.
The jh::ranges::collect adaptor provides an explicit and controlled way to materialize a lazy range into a concrete container. It represents the eager half of std::ranges::to: while to performs direct construction of a closable container, collect enforces explicit evaluation of any lazy or proxy-based range and yields a stable, value-semantic container.
C and R satisfy closable_container_for<C, R>, it delegates directly to jh::ranges::to_adaptor<C>. collectable_status deduction, supporting the four canonical insertion forms aligned with the proposed std::ranges::to: emplace_back() push_back() emplace() insert() C provides reserve() and R models sized_range, capacity is automatically preallocated. When none of the direct or implicit construction paths apply, and the range's element type is tuple-like, collect attempts a fallback reconstruction step: it unpacks the tuple-like element via jh::meta::adl_apply into emplace_back() or emplace() calls. This mechanism is unique to collect — the standard std::ranges::to does not perform such unpacking.
Here, enumerate() (implemented via jh::ranges::zip_view and std::iota) yields a tuple-like proxy (zip_reference_proxy) combining the index and string reference; collect detects that it cannot insert the proxy directly, unpacks it, and reconstructs real std::pair<size_t, std::string> objects.
collect defines the explicit evaluation boundary within a lazy pipeline — it marks where deferred computations stop and data becomes concrete. This is crucial when interacting with std::views::transform or other lazy adaptors that convert a range into a transient, consumptive stream. By forcing evaluation, collect ensures that the data is materialized and safe from dangling or deferred access.
collect does not accept additional constructor arguments. It performs data normalization only — all container-specific configuration (e.g. allocators, hashers, comparators) belongs to jh::ranges::to.
Do not use std::move() between collect and to — it provides no benefit. The two adaptors are designed to compose directly in a pipeline; move construction is handled automatically via RVO/NRVO. See the to adaptor documentation for detailed move semantics.
If your target container is a standard type that does not require extra constructor parameters (e.g. std::vector, std::set, std::unordered_map), you can use collect<C> directly as the final stage. Performance will be identical to to because, when possible, collect automatically dispatches to to_adaptor<C> internally.
jh::ranges::to for final adaptation. jh::ranges::tocollect focuses on materialization — forcing a lazy range into stable storage. to focuses on adaptation — constructing the final container, possibly with configuration parameters.
collect<V>() — eagerly realize and normalize data. to<C>(...) — adapt and construct the final container. Together they form a deterministic two-phase pipeline, separating lazy evaluation from container adaptation for clarity, safety, and composability.
collect is more permissive than to: it accepts any range that supports minimal insertion semantics, and provides additional tuple-unpacking fallback paths. However, because it forbids extra arguments, configuration such as allocators or policies must be handled by to.1.3.x
2025