16concept Printable =
requires(std::ostream& os, T
a) { os <<
a; };
19concept Elemable =
requires(T elem) {
24template<
class R,
class F> std::ostream&
range(std::ostream& os,
const R& r, F f,
const char* sep =
", ") {
25 const char* cur_sep =
"";
26 for (
const auto& elem : r) {
27 for (
auto i = cur_sep; *i !=
'\0'; ++i) os << *i;
29 if constexpr (std::is_invocable_v<
F, std::ostream&,
decltype(elem)>)
30 std::invoke(f, os, elem);
38bool match2nd(std::ostream& os,
const char* next,
const char*& s,
const char c);
81template<
class R,
class F>
struct Elem {
90std::ostream&
print(std::ostream& os,
const char* s);
92template<
class T,
class... Args> std::ostream&
print(std::ostream& os,
const char* s, T&& t, Args&&... args) {
98 if (detail::match2nd(os, next, s,
'{'))
continue;
102 while (*s !=
'\0' && *s !=
'}') spec.push_back(*s++);
103 assert(*s ==
'}' &&
"unmatched closing brace '}' in format string");
105 if constexpr (std::is_invocable_v<
decltype(t)>) {
107 }
else if constexpr (std::is_invocable_v<
decltype(t), std::ostream&>) {
109 }
else if constexpr (detail::Printable<
decltype(t)>) {
110 auto flags = std::ios_base::fmtflags(os.flags());
113 assert(
false &&
"TODO");
114 else if (spec ==
"o")
116 else if (spec ==
"d")
118 else if (spec ==
"x")
123 }
else if constexpr (detail::Elemable<
decltype(t)>) {
124 detail::range(os, t.range, t.f, spec.c_str());
125 }
else if constexpr (std::ranges::range<
decltype(t)>) {
127 os, t, [&](
const auto& x) { os << x; }, spec.c_str());
129 []<
bool flag =
false>() {
static_assert(flag,
"cannot print T t"); }
135 return print(os, s, std::forward<Args&&>(args)...);
138 if (detail::match2nd(os, next, s,
'}'))
continue;
139 assert(
false &&
"unmatched/unescaped closing brace '}' in format string");
145 assert(
false &&
"invalid format string for 's'");
150template<
class... Args> std::ostream&
println(std::ostream& os,
const char*
fmt, Args&&... args) {
151 return print(os,
fmt, std::forward<Args&&>(args)...) << std::endl;
155template<
class... Args> std::string
fmt(
const char* s, Args&&... args) {
156 std::ostringstream os;
157 print(os, s, std::forward<Args&&>(args)...);
162template<
class T = std::logic_error,
class... Args> [[noreturn]]
void error(
const char*
fmt, Args&&... args) {
163 std::ostringstream oss;
164 print(oss <<
"error: ",
fmt, std::forward<Args&&>(args)...);
169# define assertf(condition, ...) \
170 do { (void)sizeof(condition); } while (false)
172# define assertf(condition, ...) \
174 if (!(condition)) { \
175 mim::errf("{}:{}: assertion: ", __FILE__, __LINE__); \
176 mim::errln(__VA_ARGS__); \
187template<
class... Args> std::ostream&
outf (
const char*
fmt, Args&&... args) {
return print(std::cout,
fmt, std::forward<Args&&>(args)...); }
188template<
class... Args> std::ostream&
errf (
const char*
fmt, Args&&... args) {
return print(std::cerr,
fmt, std::forward<Args&&>(args)...); }
189template<
class... Args> std::ostream&
outln(
const char*
fmt, Args&&... args) {
return outf(
fmt, std::forward<Args&&>(args)...) << std::endl; }
190template<
class... Args> std::ostream&
errln(
const char*
fmt, Args&&... args) {
return errf(
fmt, std::forward<Args&&>(args)...) << std::endl; }
203 size_t indent()
const {
return indent_; }
204 std::string_view
tab()
const {
return tab_; }
211 template<
class... Args> std::ostream&
print(std::ostream& os,
const char* s, Args&&... args) {
212 for (
size_t i = 0; i < indent_; ++i) os << tab_;
213 return mim::print(os, s, std::forward<Args>(args)...);
216 template<
class... Args> std::ostream&
lnprint(std::ostream& os,
const char* s, Args&&... args) {
217 return print(os << std::endl, s, std::forward<Args>(args)...);
220 template<
class... Args> std::ostream&
println(std::ostream& os,
const char* s, Args&&... args) {
221 return print(os, s, std::forward<Args>(args)...) << std::endl;
229 [[nodiscard]]
Tab operator--(
int) { assert(indent_ > 0);
return {tab_, indent_--}; }
246 std::string_view tab_;
Keeps track of indentation level.
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)