28requires std::invocable<const F&, std::ostream&>
35 if constexpr (std::same_as<std::invoke_result_t<F const&, std::ostream&>, std::ostream&>)
36 return std::invoke(s.f_, os);
38 return std::invoke(s.f_, os), os;
56 template<
class T,
class FormatContext>
57 auto format(T
const& value, FormatContext& ctx)
const {
58 std::basic_stringstream<Char> ss;
60 return std::formatter<std::basic_string_view<Char>, Char>
::format(ss.view(), ctx);
83 constexpr int indent() const noexcept {
return indent_; }
84 constexpr std::string_view
tab() const noexcept {
return tab_; }
98 constexpr Tab&
operator--() noexcept { assert(indent_ > 0); --indent_;
return *
this; }
105 for (
int i = 0; i !=
tab.indent_; ++i)
111 std::string_view tab_;
115template<
class T,
class CharT =
char>
117 =
requires(std::basic_format_context<std::back_insert_iterator<std::basic_string<CharT>>, CharT>& ctx, T
const& v) {
118 std::formatter<std::remove_cvref_t<T>, CharT>{}.format(v, ctx);
123template<std::ranges::input_range R>
127 using View = std::views::all_t<R>;
130 : range_(std::views::all(std::forward<R>(
range)))
133 const auto&
range()
const {
return range_; }
134 std::string_view
sep()
const {
return sep_; }
137 for (std::string_view
sep{};
const auto& elem : j.range_) {
146 std::string_view sep_;
159struct std::formatter<
fe::
Join<R>> {
160 using elem_t = std::remove_cvref_t<std::ranges::range_reference_t<std::views::all_t<R>>>;
161 std::formatter<elem_t> elem_fmt;
163 constexpr auto parse(std::format_parse_context& ctx) {
return elem_fmt.parse(ctx); }
165 template<
class FormatContext>
166 auto format(
const fe::Join<R>& j, FormatContext& ctx)
const {
167 auto out = ctx.out();
168 for (std::string_view sep = {};
const auto& elem : j.
range()) {
169 out = std::ranges::copy(sep, out).out;
171 out = elem_fmt.format(elem, ctx);
189# define assertf(condition, ...) \
191 (void)sizeof(condition); \
194# define assertf(condition, ...) \
196 if (!(condition)) { \
197 std::println(std::cerr, "{}:{}: assertion `{}` failed", __FILE__, __LINE__, #condition); \
198 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++() noexcept
friend std::ostream & operator<<(std::ostream &os, Tab tab)
constexpr Tab & operator-=(int indent) noexcept
Tab operator+(int indent) const noexcept
Tab(std::string_view tab={"\t"}, int indent=0)
constexpr int indent() const noexcept
Tab operator-(int indent) const noexcept
constexpr Tab & operator--() noexcept
StreamFn(F) -> StreamFn< F >
basic_ostream_formatter< char > ostream_formatter
Join(R &&, std::string_view=", ") -> Join< R >