29requires std::invocable<const F&, std::ostream&>
class StreamFn {
35 std::invoke(s.f_, os);
54 auto format(
const auto& value,
auto& ctx)
const {
55 std::basic_stringstream<Char> ss;
57 return std::formatter<std::basic_string_view<Char>, Char>
::format(ss.view(), ctx);
69 constexpr Tab(std::string_view
tab = {
"\t"},
int indent = 0)
noexcept
75 static constexpr Tab spaces() noexcept {
return Tab(std::string_view(
" ")); }
80 constexpr int indent() const noexcept {
return indent_; }
81 constexpr std::string_view
tab() const noexcept {
return tab_; }
95 constexpr Tab&
operator--() noexcept { assert(indent_ > 0); --indent_;
return *
this; }
102 for (
int i = 0; i !=
tab.indent_; ++i)
108 std::string_view tab_;
114 =
requires(std::format_context& ctx,
const T& v) { std::formatter<std::remove_cvref_t<T>>{}.format(v, ctx); };
118template<std::ranges::input_range R>
121 using View = std::views::all_t<R>;
127 const auto&
range()
const {
return range_; }
128 std::string_view
sep()
const {
return sep_; }
131 for (std::string_view
sep{};
const auto& elem : j.range_) {
140 std::string_view sep_;
153struct std::formatter<
fe::
Join<R>> {
154 using elem_t = std::remove_cvref_t<std::ranges::range_reference_t<std::views::all_t<R>>>;
155 std::formatter<elem_t> elem_fmt;
157 constexpr auto parse(std::format_parse_context& ctx) {
return elem_fmt.parse(ctx); }
159 auto format(
const fe::Join<R>& j,
auto& ctx)
const {
160 auto out = ctx.out();
161 for (std::string_view sep = {};
const auto& elem : j.
range()) {
162 out = std::ranges::copy(sep, out).out;
164 out = elem_fmt.format(elem, ctx);
187# define assertf(condition, ...) \
189 (void)sizeof(condition); \
192# define assertf(condition, ...) \
194 if (!(condition)) { \
195 std::println(std::cerr, "{}:{}: assertion `{}` failed", __FILE__, __LINE__, #condition); \
196 std::println(std::cerr, __VA_ARGS__); \
Join elements of range with sep.
const auto & range() const
std::string_view sep() const
friend std::ostream & operator<<(std::ostream &os, const Join &j)
Join(R &&range, std::string_view sep=", ")
std::views::all_t< R > View
Wrap a callable f(std::ostream&) -> std::ostream& so it streams via operator<< and std::format.
friend std::ostream & operator<<(std::ostream &os, StreamFn const &s)
constexpr Tab & operator+=(int indent) noexcept
constexpr std::string_view tab() const noexcept
constexpr Tab operator-(int indent) const noexcept
constexpr Tab & operator++() noexcept
friend std::ostream & operator<<(std::ostream &os, Tab tab)
constexpr Tab & operator-=(int indent) noexcept
constexpr int indent() const noexcept
constexpr Tab(const Tab &)=default
static constexpr Tab spaces() noexcept
constexpr Tab & operator--() noexcept
constexpr Tab operator+(int indent) const noexcept
constexpr Tab(std::string_view tab={"\t"}, int indent=0) noexcept
Span< const T, N > View
Read-only Span; use Span itself, if you want to write through its elements.
basic_ostream_formatter< char > ostream_formatter
Join(R &&, std::string_view=", ") -> Join< R >