16concept Printable =
requires(std::ostream& os, T
a) { os <<
a; };
19concept Elemable =
requires(T elem) {
24template<
class R,
class F>
25std::ostream& range(std::ostream& os,
const R& r, F f,
const char* sep =
", ") {
26 const char* cur_sep =
"";
27 for (
const auto& elem : r) {
28 for (
auto i = cur_sep; *i !=
'\0'; ++i)
31 if constexpr (std::is_invocable_v<
F, std::ostream&,
decltype(elem)>)
32 std::invoke(f, os, elem);
40bool match2nd(std::ostream& os,
const char* next,
const char*& s,
const char c);
84template<
class R,
class F>
94std::ostream&
print(std::ostream& os,
const char* s);
96template<
class T,
class... Args>
97std::ostream&
print(std::ostream& os,
const char* s, T&& t, Args&&... args) {
103 if (detail::match2nd(os, next, s,
'{'))
continue;
107 while (*s !=
'\0' && *s !=
'}')
108 spec.push_back(*s++);
109 assert(*s ==
'}' &&
"unmatched closing brace '}' in format string");
111 if constexpr (std::is_invocable_v<
decltype(t)>) {
113 }
else if constexpr (std::is_invocable_v<
decltype(t), std::ostream&>) {
115 }
else if constexpr (detail::Printable<
decltype(t)>) {
116 auto flags = std::ios_base::fmtflags(os.flags());
119 assert(
false &&
"TODO");
120 else if (spec ==
"o")
122 else if (spec ==
"d")
124 else if (spec ==
"x")
129 }
else if constexpr (detail::Elemable<
decltype(t)>) {
130 detail::range(os, t.range, t.f, spec.c_str());
131 }
else if constexpr (std::ranges::range<
decltype(t)>) {
133 os, t, [&](
const auto& x) { os << x; }, spec.c_str());
135 []<
bool flag =
false>() {
static_assert(flag,
"cannot print T t"); }
141 return print(os, s, std::forward<Args>(args)...);
144 if (detail::match2nd(os, next, s,
'}'))
continue;
145 assert(
false &&
"unmatched/unescaped closing brace '}' in format string");
151 assert(
false &&
"invalid format string for 's'");
156template<
class... Args>
157std::ostream&
println(std::ostream& os,
const char*
fmt, Args&&... args) {
158 return print(os,
fmt, std::forward<Args>(args)...) << std::endl;
162template<
class... Args>
163std::string
fmt(
const char* s, Args&&... args) {
164 std::ostringstream os;
165 print(os, s, std::forward<Args>(args)...);
170template<
class T = std::logic_error,
class... Args>
171[[noreturn]]
void error(
const char*
fmt, Args&&... args) {
172 std::ostringstream oss;
173 print(oss <<
"error: ",
fmt, std::forward<Args>(args)...);
178# define assertf(condition, ...) \
180 (void)sizeof(condition); \
183# define assertf(condition, ...) \
185 if (!(condition)) { \
186 mim::errf("{}:{}: assertion: ", __FILE__, __LINE__); \
187 mim::errln(__VA_ARGS__); \
198template<
class... Args> std::ostream&
outf (
const char*
fmt, Args&&... args) {
return print(std::cout,
fmt, std::forward<Args>(args)...); }
199template<
class... Args> std::ostream&
errf (
const char*
fmt, Args&&... args) {
return print(std::cerr,
fmt, std::forward<Args>(args)...); }
200template<
class... Args> std::ostream&
outln(
const char*
fmt, Args&&... args) {
return outf(
fmt, std::forward<Args>(args)...) << std::endl; }
201template<
class... Args> std::ostream&
errln(
const char*
fmt, Args&&... args) {
return errf(
fmt, std::forward<Args>(args)...) << std::endl; }
214 size_t indent()
const {
return indent_; }
215 std::string_view
tab()
const {
return tab_; }
222 template<
class... Args>
223 std::ostream&
print(std::ostream& os,
const char* s, Args&&... args) {
224 for (
size_t i = 0; i < indent_; ++i)
226 return mim::print(os, s, std::forward<Args>(args)...);
229 template<
class... Args>
230 std::ostream&
lnprint(std::ostream& os,
const char* s, Args&&... args) {
231 return print(os << std::endl, s, std::forward<Args>(args)...);
234 template<
class... Args>
235 std::ostream&
println(std::ostream& os,
const char* s, Args&&... args) {
236 return print(os, s, std::forward<Args>(args)...) << std::endl;
244 [[nodiscard]]
Tab operator--(
int) { assert(indent_ > 0);
return {tab_, indent_--}; }
261 std::string_view tab_;
Tab operator-(size_t indent) const
Tab & operator=(size_t indent)
std::string_view tab() const
std::ostream & println(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but appends a std::endl to os.
Tab & operator=(std::string_view tab)
Tab & operator-=(size_t indent)
std::ostream & lnprint(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but prepends a std::endl to os.
Tab & operator+=(size_t indent)
Tab(std::string_view tab={" "}, size_t indent=0)
Tab operator+(size_t indent) const
std::ostream & print(std::ostream &os, const char *s, Args &&... args)
std::ostream & print(std::ostream &os, const char *s)
Base case.
std::string fmt(const char *s, Args &&... args)
Wraps mim::print to output a formatted std:string.
void error(Loc loc, const char *f, Args &&... args)
std::ostream & errf(const char *fmt, Args &&... args)
std::ostream & outf(const char *fmt, Args &&... args)
std::ostream & outln(const char *fmt, Args &&... args)
std::ostream & errln(const char *fmt, Args &&... args)
std::ostream & println(std::ostream &os, const char *fmt, Args &&... args)
As above but end with std::endl.
Elem(const R &range, const F &f)