microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
filter_view.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
17#include "../microfmt.hpp"
18#include <cstddef>
19#include <iterator>
20#include <string_view>
21#include <type_traits>
22#include <utility>
23
24namespace microfmt {
25
27template <typename Range, typename Predicate> struct RELOCO_POINTER filtered_range_view {
28 const Range &range;
29 Predicate predicate;
30 char open_delim{'['};
31 char close_delim{']'};
32 microfmt::string_view separator{", "};
33};
34
36template <typename T, typename Predicate> struct RELOCO_POINTER filtered_pointer_range_view {
37 const T *data{nullptr};
38 size_t count{0};
39 Predicate predicate;
40 char open_delim{'['};
41 char close_delim{']'};
42 microfmt::string_view separator{", "};
43};
44
46template <typename Range, typename Predicate>
47[[nodiscard]] constexpr auto filter(const Range &rng, Predicate &&pred) noexcept {
48 return filtered_range_view<Range, std::decay_t<Predicate>>{rng, std::forward<Predicate>(pred)};
49}
50
51template <typename Range, typename Predicate, std::enable_if_t<!std::is_lvalue_reference_v<Range>, int> = 0>
52[[nodiscard]] constexpr auto filter(Range &&, Predicate &&) noexcept = delete;
53
55template <typename T, typename Predicate>
56[[nodiscard]] constexpr auto filter(const T *ptr, size_t count, Predicate &&pred) noexcept {
57 return filtered_pointer_range_view<T, std::decay_t<Predicate>>{ptr, ptr == nullptr ? 0 : count,
58 std::forward<Predicate>(pred)};
59}
60
67template <typename Range, typename Predicate> struct formatter<filtered_range_view<Range, Predicate>> {
68 char open_c{'['};
69 char close_c{']'};
70 microfmt::string_view forwarded_spec{""};
71
72 constexpr void parse(format_parse_context &ctx) noexcept {
73 auto spec = ctx.spec();
74 if (spec.empty())
75 return;
76
77 size_t i = 0;
78 if (spec[0] == 'b' || spec[0] == 'B') {
79 open_c = '[';
80 close_c = ']';
81 i = 1;
82 } else if (spec[0] == 'c' || spec[0] == 'C') {
83 open_c = '{';
84 close_c = '}';
85 i = 1;
86 } else if (spec[0] == 'n' || spec[0] == 'N') {
87 open_c = '\0';
88 close_c = '\0';
89 i = 1;
90 }
91 forwarded_spec = spec.substr(i);
92 }
93
94 void format(const filtered_range_view<Range, Predicate> &fv, const sink &out) const noexcept {
95 if (open_c != '\0') {
96 out.put(open_c);
97 }
98
99 using ElementReference = decltype(*std::begin(fv.range));
100 using ElemType = typename std::remove_cv<typename std::remove_reference<ElementReference>::type>::type;
102 format_parse_context elem_ctx(forwarded_spec);
103 elem_fmt.parse(elem_ctx);
104
105 size_t matched_count = 0;
106 for (const auto &item : fv.range) {
107 if (fv.predicate(item)) {
108 if (matched_count++ > 0) {
109 out.write(fv.separator);
110 }
111 elem_fmt.format(item, out);
112 }
113 }
114
115 if (close_c != '\0') {
116 out.put(close_c);
117 }
118 }
119};
120
126template <typename T, typename Predicate> struct formatter<filtered_pointer_range_view<T, Predicate>> {
127 char open_c{'['};
128 char close_c{']'};
129 microfmt::string_view forwarded_spec{""};
130
131 constexpr void parse(format_parse_context &ctx) noexcept {
132 auto spec = ctx.spec();
133 if (spec.empty())
134 return;
135
136 size_t i = 0;
137 if (spec[0] == 'b' || spec[0] == 'B') {
138 open_c = '[';
139 close_c = ']';
140 i = 1;
141 } else if (spec[0] == 'c' || spec[0] == 'C') {
142 open_c = '{';
143 close_c = '}';
144 i = 1;
145 } else if (spec[0] == 'n' || spec[0] == 'N') {
146 open_c = '\0';
147 close_c = '\0';
148 i = 1;
149 }
150 forwarded_spec = spec.substr(i);
151 }
152
153 void format(const filtered_pointer_range_view<T, Predicate> &fv, const sink &out) const noexcept {
154 if (open_c != '\0') {
155 out.put(open_c);
156 }
157
159 format_parse_context elem_ctx(forwarded_spec);
160 elem_fmt.parse(elem_ctx);
161
162 size_t matched_count = 0;
163 for (size_t i = 0; i < fv.count; ++i) {
164 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
165 const T &item = fv.data[i];
166 RELOCO_END_UNSAFE_BUFFER_USAGE;
167
168 if (fv.predicate(item)) {
169 if (matched_count++ > 0) {
170 out.write(fv.separator);
171 }
172 elem_fmt.format(item, out);
173 }
174 }
175
176 if (close_c != '\0') {
177 out.put(close_c);
178 }
179 }
180};
181
182} // namespace microfmt
Definition microfmt.hpp:881
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr auto filter(const Range &rng, Predicate &&pred) noexcept
Definition filter_view.hpp:47
Drop-in replacement for a formatter<T> underlying_formatter; member used by container/wrapper formatt...
Definition microfmt.hpp:1433
constexpr void parse(format_parse_context &ctx) noexcept
Definition microfmt.hpp:1445
void format(const T &value, const sink &out) const noexcept
Definition microfmt.hpp:1447
Definition filter_view.hpp:36
Predicate predicate
Definition filter_view.hpp:39
Definition filter_view.hpp:27
const Range & range
Definition filter_view.hpp:28
Predicate predicate
Definition filter_view.hpp:29
void format(const filtered_pointer_range_view< T, Predicate > &fv, const sink &out) const noexcept
Definition filter_view.hpp:153
constexpr void parse(format_parse_context &ctx) noexcept
Definition filter_view.hpp:131
constexpr void parse(format_parse_context &ctx) noexcept
Definition filter_view.hpp:72
void format(const filtered_range_view< Range, Predicate > &fv, const sink &out) const noexcept
Definition filter_view.hpp:94
Definition microfmt.hpp:985