3#include <tess/block/block.h>
22 constexpr void record_block()
noexcept { ++blocks_read_; }
23 constexpr void record_item()
noexcept { ++items_read_; }
24 constexpr void record_filtered()
noexcept { ++items_filtered_; }
25 constexpr void record_emitted()
noexcept { ++items_emitted_; }
26 constexpr void record_materialization()
noexcept { ++materializations_; }
27 constexpr void record_capacity_failure()
noexcept { ++capacity_failures_; }
29 [[nodiscard]]
constexpr auto blocks_read()
const noexcept -> std::uint64_t {
32 [[nodiscard]]
constexpr auto items_read()
const noexcept -> std::uint64_t {
35 [[nodiscard]]
constexpr auto items_filtered()
const noexcept
37 return items_filtered_;
39 [[nodiscard]]
constexpr auto items_emitted()
const noexcept -> std::uint64_t {
40 return items_emitted_;
42 [[nodiscard]]
constexpr auto materializations()
const noexcept
44 return materializations_;
46 [[nodiscard]]
constexpr auto capacity_failures()
const noexcept
48 return capacity_failures_;
52 std::uint64_t blocks_read_ = 0;
53 std::uint64_t items_read_ = 0;
54 std::uint64_t items_filtered_ = 0;
55 std::uint64_t items_emitted_ = 0;
56 std::uint64_t materializations_ = 0;
57 std::uint64_t capacity_failures_ = 0;
62 std::size_t written = 0;
63 std::uint64_t required = 0;
64 bool capacity_exhausted =
false;
67template <
typename ChunkView>
78template <
typename Context>
79struct BlockTileSource {
80 using view_type =
decltype(std::declval<const Context&>().chunk_view(
81 std::declval<ChunkKey>()));
90 template <
typename Sink>
91 void for_each(Sink&& sink) {
93 context.for_each_chunk([&](
auto view) {
94 if (diagnostics !=
nullptr) {
95 diagnostics->record_block();
97 view.for_each_tile([&](LocalTileId
id, LocalCoord3 local) {
98 if (diagnostics !=
nullptr) {
99 diagnostics->record_item();
102 value_type{view, id, local, view.world_coord(local)});
108template <
typename Context>
109struct BlockChunkSource {
110 using value_type =
decltype(std::declval<const Context&>().chunk_view(
111 std::declval<ChunkKey>()));
116 PipelineDiagnostics* diagnostics =
nullptr;
118 template <
typename Sink>
119 void for_each(Sink&& sink) {
120 auto&& output = sink;
121 context.for_each_chunk([&](
auto view) {
122 if (diagnostics !=
nullptr) {
123 diagnostics->record_block();
124 diagnostics->record_item();
126 std::invoke(output, view);
133 using value_type = T;
135 std::span<const T> values;
136 PipelineDiagnostics* diagnostics =
nullptr;
138 template <
typename Sink>
139 void for_each(Sink&& sink) {
140 auto&& output = sink;
141 for (
const auto& value : values) {
142 if (diagnostics !=
nullptr) {
143 diagnostics->record_item();
145 std::invoke(output, value);
150template <
typename Source,
typename Predicate>
152 using value_type =
typename Source::value_type;
156 PipelineDiagnostics* diagnostics =
nullptr;
158 template <
typename Sink>
159 void for_each(Sink&& sink) {
160 auto&& output = sink;
161 source.for_each([&](
auto&& value) {
162 if (std::invoke(predicate, value)) {
163 std::invoke(output, std::forward<
decltype(value)>(value));
164 }
else if (diagnostics !=
nullptr) {
165 diagnostics->record_filtered();
171template <
typename Source,
typename Mapper>
173 using value_type = std::remove_cvref_t<
174 std::invoke_result_t<Mapper&, typename Source::value_type>>;
179 template <
typename Sink>
180 void for_each(Sink&& sink) {
181 auto&& output = sink;
182 source.for_each([&](
auto&& value) {
184 std::invoke(mapper, std::forward<
decltype(value)>(value)));
189template <
typename Source,
typename Mapper>
190struct FlatMapSource {
191 using range_type = std::remove_cvref_t<
192 std::invoke_result_t<Mapper&, typename Source::value_type>>;
194 std::remove_cvref_t<std::ranges::range_reference_t<range_type>>;
199 template <
typename Sink>
200 void for_each(Sink&& sink) {
201 auto&& output = sink;
202 source.for_each([&](
auto&& value) {
205 auto&& range = std::invoke(mapper, std::forward<
decltype(value)>(value));
206 for (
auto&& item : range) {
207 std::invoke(output, std::forward<
decltype(item)>(item));
215template <
typename Source>
219 using value_type =
typename Source::value_type;
222 : source_(std::move(source)), diagnostics_(diagnostics) {}
224 template <
typename Predicate>
225 [[nodiscard]]
auto filter(Predicate predicate) && {
226 using Filter = detail::FilterSource<Source, Predicate>;
227 return Pipeline<Filter>{
228 Filter{std::move(source_), std::move(predicate), diagnostics_},
232 template <
typename Mapper>
233 [[nodiscard]]
auto map(Mapper mapper) && {
234 using Map = detail::MapSource<Source, Mapper>;
235 return Pipeline<Map>{Map{std::move(source_), std::move(mapper)},
239 template <
typename Mapper>
240 [[nodiscard]]
auto flat_map(Mapper mapper) && {
241 using FlatMap = detail::FlatMapSource<Source, Mapper>;
242 return Pipeline<FlatMap>{FlatMap{std::move(source_), std::move(mapper)},
246 template <
typename Fn>
247 void for_each(Fn&& fn) {
249 source_.for_each([&](
auto&& value) {
250 if (diagnostics_ !=
nullptr) {
251 diagnostics_->record_emitted();
253 std::invoke(output, std::forward<
decltype(value)>(value));
257 template <
typename Result,
typename Reducer>
258 [[nodiscard]]
auto reduce(Result initial, Reducer reducer) -> Result {
259 auto result = std::move(initial);
260 source_.for_each([&](
auto&& value) {
261 if (diagnostics_ !=
nullptr) {
262 diagnostics_->record_emitted();
264 result = std::invoke(reducer, std::move(result),
265 std::forward<
decltype(value)>(value));
270 template <
typename Output, std::
size_t Extent>
271 [[nodiscard]]
auto collect_into(std::span<Output, Extent> output)
274 source_.for_each([&](
auto&& value) {
275 if (result.written < output.size()) {
276 output[result.written++] = std::forward<decltype(value)>(value);
279 if (diagnostics_ !=
nullptr) {
280 diagnostics_->record_emitted();
283 result.capacity_exhausted = result.required > output.size();
284 if (result.capacity_exhausted && diagnostics_ !=
nullptr) {
285 diagnostics_->record_capacity_failure();
290 template <
typename Output, std::
size_t Size>
291 [[nodiscard]]
auto collect_into(std::array<Output, Size>& output)
293 return collect_into(std::span<Output, Size>{output});
296 [[nodiscard]]
auto to_sequence_allocating() -> std::vector<value_type> {
297 if (diagnostics_ !=
nullptr) {
298 diagnostics_->record_materialization();
300 auto output = std::vector<value_type>{};
301 source_.for_each([&](
auto&& value) {
302 output.push_back(std::forward<
decltype(value)>(value));
303 if (diagnostics_ !=
nullptr) {
304 diagnostics_->record_emitted();
315template <
typename Context>
317[[nodiscard]]
auto block_tiles(Context context,
319 using Source = detail::BlockTileSource<Context>;
320 return Pipeline<Source>{Source{std::move(context), diagnostics}, diagnostics};
323template <
typename Context>
325[[nodiscard]]
auto block_tiles(
const Context& context,
327 return block_tiles(context, &diagnostics);
330template <
typename Context>
332[[nodiscard]]
auto block_chunks(Context context,
334 using Source = detail::BlockChunkSource<Context>;
335 return Pipeline<Source>{Source{std::move(context), diagnostics}, diagnostics};
338template <
typename Context>
340[[nodiscard]]
auto block_chunks(
const Context& context,
342 return block_chunks(context, &diagnostics);
345template <
typename T, std::
size_t Extent>
347[[nodiscard]]
auto pipeline_from(std::span<T, Extent> values,
349 using Item = std::remove_cv_t<T>;
350 using Source = detail::SpanSource<Item>;
352 Source{std::span<const Item>{values.data(), values.size()}, diagnostics},
Caller-owned counters for one or more lazy pipeline terminal runs.
Definition pipeline.h:18
Definition pipeline.h:217
Reports bounded materialization occupancy and required capacity.
Definition pipeline.h:61