initial format string support
This commit is contained in:
parent
809e4825ae
commit
011aea6fbb
87
octa/format.hh
Normal file
87
octa/format.hh
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* Format strings for OctaSTD.
|
||||
*
|
||||
* This file is part of OctaSTD. See COPYING.md for futher information.
|
||||
*/
|
||||
|
||||
#ifndef OCTA_FORMAT_HH
|
||||
#define OCTA_FORMAT_HH
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "octa/algorithm.hh"
|
||||
#include "octa/string.hh"
|
||||
|
||||
namespace octa {
|
||||
|
||||
template<typename R>
|
||||
static inline void write_val(R &writer, const char *val) {
|
||||
while (*val) writer.put(*val++);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
static inline void write_val(R &writer, const octa::String &val) {
|
||||
for (octa::Size i = 0; i < val.size(); ++i) writer.put(val[i]);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
static inline void write_val(R &writer, char val) {
|
||||
writer.put(val);
|
||||
}
|
||||
|
||||
template<typename R, typename T>
|
||||
static inline void write_val(R &writer, const T &val) {
|
||||
write_val(writer, octa::to_string(val));
|
||||
}
|
||||
|
||||
template<typename R, typename T, typename ...A>
|
||||
static inline void write_idx(R &writer, octa::Size idx, const T &v) {
|
||||
if (idx) assert(false && "not enough format args");
|
||||
write_val(writer, v);
|
||||
}
|
||||
|
||||
template<typename R, typename T, typename ...A>
|
||||
static inline void write_idx(R &writer, octa::Size idx, const T &v,
|
||||
A &&...args) {
|
||||
if (idx) {
|
||||
write_idx(writer, idx - 1, octa::forward<A>(args)...);
|
||||
return;
|
||||
}
|
||||
write_val(writer, v);
|
||||
}
|
||||
|
||||
|
||||
template<typename R, typename ...A>
|
||||
static inline octa::Size formatted_write(R writer, const char *fmt,
|
||||
A &&...args) {
|
||||
octa::Size argidx = 0, retn = 0;
|
||||
while (*fmt) {
|
||||
if (*fmt == '{') {
|
||||
octa::Size needidx = argidx;
|
||||
if (*++fmt != '}') {
|
||||
char idx[8] = { '\0' };
|
||||
for (octa::Size i = 0; isdigit(*fmt); ++i)
|
||||
idx[i] = *fmt++;
|
||||
assert((*fmt == '}') && "malformed format string");
|
||||
needidx = atoi(idx);
|
||||
} else ++argidx;
|
||||
++fmt;
|
||||
retn = octa::max(needidx, retn);
|
||||
write_idx(writer, needidx, octa::forward<A>(args)...);
|
||||
continue;
|
||||
}
|
||||
writer.put(*fmt++);
|
||||
}
|
||||
return retn + 1;
|
||||
}
|
||||
|
||||
template<typename R, typename ...A>
|
||||
octa::Size formatted_write(R writer, const octa::String &fmt, A &&...args) {
|
||||
return formatted_write(writer, fmt.data(), octa::forward<A>(args)...);
|
||||
}
|
||||
|
||||
} /* namespace octa */
|
||||
|
||||
#endif
|
47
octa/io.hh
47
octa/io.hh
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "octa/string.hh"
|
||||
#include "octa/stream.hh"
|
||||
#include "octa/format.hh"
|
||||
|
||||
namespace octa {
|
||||
|
||||
|
@ -151,6 +152,52 @@ static inline void writeln(const T &v, const A &...args) {
|
|||
putc('\n', ::stdout);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
struct FormatOutRange: octa::OutputRange<char> {
|
||||
FormatOutRange(): needed(0) {}
|
||||
octa::Size needed;
|
||||
char buf[512];
|
||||
void put(char v) {
|
||||
if (needed < sizeof(buf))
|
||||
buf[needed] = v;
|
||||
++needed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ...A>
|
||||
static inline void writef(const char *fmt, A &&...args) {
|
||||
octa::detail::FormatOutRange writer1;
|
||||
octa::formatted_write<octa::detail::FormatOutRange &>(writer1, fmt,
|
||||
octa::forward<A>(args)...);
|
||||
if (writer1.needed < sizeof(writer1.buf)) {
|
||||
fwrite(writer1.buf, 1, writer1.needed, ::stdout);
|
||||
return;
|
||||
}
|
||||
octa::String s;
|
||||
s.reserve(writer1.needed);
|
||||
s[writer1.needed] = '\0';
|
||||
octa::formatted_write(s.iter(), fmt, octa::forward<A>(args)...);
|
||||
fwrite(s.data(), 1, writer1.needed, ::stdout);
|
||||
}
|
||||
|
||||
template<typename ...A>
|
||||
static inline void writef(const octa::String &fmt, A &&...args) {
|
||||
writef(fmt.data(), octa::forward<A>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...A>
|
||||
static inline void writefln(const char *fmt, A &&...args) {
|
||||
writef(fmt, octa::forward<A>(args)...);
|
||||
putc('\n', ::stdout);
|
||||
}
|
||||
|
||||
template<typename ...A>
|
||||
static inline void writefln(const octa::String &fmt, A &&...args) {
|
||||
writef(fmt, octa::forward<A>(args)...);
|
||||
putc('\n', ::stdout);
|
||||
}
|
||||
|
||||
} /* namespace octa */
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue