support for formatting tuples in format strings via %<contents%>

master
Daniel Kolesa 2017-02-20 20:14:26 +01:00
parent 3f983afae5
commit 1e1f6d63a2
2 changed files with 72 additions and 28 deletions

View File

@ -43,6 +43,7 @@ struct Bar {
int main() { int main() {
std::vector<int> x = { 5, 10, 15, 20 }; std::vector<int> x = { 5, 10, 15, 20 };
writefln("[%(%s|%)]", x); writefln("[%(%s|%)]", x);
writefln("%s", x);
int y[] = { 2, 4, 8, 16, 32 }; int y[] = { 2, 4, 8, 16, 32 };
writefln("{ %(%s, %) }", y); writefln("{ %(%s, %) }", y);
@ -62,6 +63,12 @@ int main() {
* # flag expands the element into multiple values * # flag expands the element into multiple values
*/ */
writefln("{ %-#(%s: %d, %) }", m); writefln("{ %-#(%s: %d, %) }", m);
/* without expansion */
writefln("{ %(%s, %) }", m);
/* tuple formatting */
std::tuple<std::string, int, float> tup{"hello world", 1337, 3.14f};
writefln("the tuple contains %<%s, %d, %f%>.", tup);
/* tuple format test */ /* tuple format test */
std::tuple<int, float, char const *> xt[] = { std::tuple<int, float, char const *> xt[] = {

View File

@ -276,6 +276,7 @@ struct format_spec {
string_range nested() const { return p_nested; } string_range nested() const { return p_nested; }
string_range nested_sep() const { return p_nested_sep; } string_range nested_sep() const { return p_nested_sep; }
bool is_tuple() const { return p_is_tuple; }
bool is_nested() const { return p_is_nested; } bool is_nested() const { return p_is_nested; }
bool nested_escape() const { return p_nested_escape; } bool nested_escape() const { return p_nested_escape; }
@ -310,6 +311,7 @@ private:
byte p_index = 0; byte p_index = 0;
bool p_is_tuple = false;
bool p_is_nested = false; bool p_is_nested = false;
bool p_nested_escape = false; bool p_nested_escape = false;
@ -328,7 +330,7 @@ private:
return false; return false;
} }
bool read_spec_range() { bool read_spec_range(bool tuple = false) {
int sflags = p_flags; int sflags = p_flags;
p_nested_escape = !(sflags & FMT_FLAG_DASH); p_nested_escape = !(sflags & FMT_FLAG_DASH);
p_fmt.pop_front(); p_fmt.pop_front();
@ -347,6 +349,7 @@ private:
/* find delimiter or ending */ /* find delimiter or ending */
string_range begin_delim(p_fmt); string_range begin_delim(p_fmt);
string_range p = find(begin_delim, '%'); string_range p = find(begin_delim, '%');
char need = tuple ? '>' : ')';
for (; !p.empty(); p = find(p, '%')) { for (; !p.empty(); p = find(p, '%')) {
p.pop_front(); p.pop_front();
/* escape, skip */ /* escape, skip */
@ -355,20 +358,26 @@ private:
continue; continue;
} }
/* found end, in that case delimiter is after spec */ /* found end, in that case delimiter is after spec */
if (p.front() == ')') { if (p.front() == need) {
p_nested = begin_inner.slice( p_is_tuple = tuple;
0, &begin_delim[0] - &begin_inner[0] if (tuple) {
); p_nested = begin_inner.slice(0, &p[0] - &begin_inner[0] - 1);
p_nested_sep = begin_delim.slice( p_nested_sep = nullptr;
0, &p[0] - &begin_delim[0] - 1 } else {
); p_nested = begin_inner.slice(
0, &begin_delim[0] - &begin_inner[0]
);
p_nested_sep = begin_delim.slice(
0, &p[0] - &begin_delim[0] - 1
);
}
p.pop_front(); p.pop_front();
p_fmt = p; p_fmt = p;
p_is_nested = true; p_is_nested = true;
return true; return true;
} }
/* found actual delimiter start... */ /* found actual delimiter start... */
if (p.front() == '|') { if ((p.front() == '|') && !tuple) {
p_nested = begin_inner.slice(0, &p[0] - &begin_inner[0] - 1); p_nested = begin_inner.slice(0, &p[0] - &begin_inner[0] - 1);
p.pop_front(); p.pop_front();
p_nested_sep = p; p_nested_sep = p;
@ -427,9 +436,12 @@ private:
} }
} }
/* range/array formatting */ /* range/array/tuple formatting */
if ((p_fmt.front() == '(') && (havepos || !(ndig - skipd))) { if (
return read_spec_range(); ((p_fmt.front() == '(') || (p_fmt.front() == '<')) &&
(havepos || !(ndig - skipd))
) {
return read_spec_range(p_fmt.front() == '<');
} }
/* parse width */ /* parse width */
@ -810,18 +822,6 @@ private:
} }
} }
template<size_t I, size_t N, typename R, typename T>
void write_tuple_val(
R &writer, bool escape, string_range sep, T const &tup
) const {
format_spec sp{"%s", escape};
sp.write_fmt(writer, std::get<I>(tup));
if constexpr(I < (N - 1)) {
range_put_all(writer, sep);
write_tuple_val<I + 1, N>(writer, escape, sep, tup);
}
}
/* range writer */ /* range writer */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
void write_range( void write_range(
@ -839,6 +839,39 @@ private:
} }
} }
template<size_t I, size_t N, typename R, typename T>
void write_tuple_val(
R &writer, bool escape, string_range sep, T const &tup
) const {
format_spec sp{"%s", escape};
sp.write_fmt(writer, std::get<I>(tup));
if constexpr(I < (N - 1)) {
range_put_all(writer, sep);
write_tuple_val<I + 1, N>(writer, escape, sep, tup);
}
}
template<typename R, typename T, typename ...A>
void write_tuple(
R &writer, size_t idx, T const &val, A const &...args
) {
if (idx) {
if constexpr(!sizeof...(A)) {
throw format_error{"not enough format arguments"};
} else {
write_tuple(writer, idx - 1, args...);
}
} else {
if constexpr(detail::is_tuple_like<T>) {
std::apply([this, &writer, &val](auto const &...vals) mutable {
this->write_fmt(writer, vals...);
}, val);
} else {
throw format_error{"invalid value for tuple format"};
}
}
}
template<typename R, typename ...A> template<typename R, typename ...A>
void write_fmt(R &writer, A const &...args) { void write_fmt(R &writer, A const &...args) {
size_t argidx = 1; size_t argidx = 1;
@ -850,10 +883,14 @@ private:
} }
/* FIXME: figure out a better way */ /* FIXME: figure out a better way */
format_spec nspec(nested(), nested_escape()); format_spec nspec(nested(), nested_escape());
nspec.write_range( if (is_tuple()) {
writer, argpos - 1, (flags() & FMT_FLAG_HASH), nspec.write_tuple(writer, argpos - 1, args...);
nested_sep(), args... } else {
); nspec.write_range(
writer, argpos - 1, (flags() & FMT_FLAG_HASH),
nested_sep(), args...
);
}
continue; continue;
} }
if (!argpos) { if (!argpos) {