From ad2d69e83dcc79028e11885ae88293a70ce8b702 Mon Sep 17 00:00:00 2001 From: q66 Date: Thu, 23 Jul 2015 00:40:07 +0100 Subject: [PATCH] use a sink for to_string methods on objects (no extra allocs) --- ostd/format.hh | 31 ++++--------------------------- ostd/string.hh | 46 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/ostd/format.hh b/ostd/format.hh index aed8f2f..90f7e5c 100644 --- a/ostd/format.hh +++ b/ostd/format.hh @@ -595,29 +595,6 @@ namespace detail { return ret; } - template - struct FmtWriteRange: OutputRange, char> { - FmtWriteRange() = delete; - FmtWriteRange(R &out): p_out(out), p_written(0) {} - bool put(char v) { - bool ret = p_out.put(v); - p_written += ret; - return ret; - } - Size put_n(const char *v, Size n) { - Size ret = p_out.put_n(v, n); - p_written += ret; - return ret; - } - Size put_string(ConstCharRange r) { - return put_n(&r[0], r.size()); - } - Size get_written() const { return p_written; } - private: - R &p_out; - Size p_written; - }; - template static True test_tofmt(decltype(to_format(declval(), declval(), @@ -768,7 +745,7 @@ namespace detail { !IsArithmetic::value && !IsConstructible::value && FmtTostrTest::value && - !FmtTofmtTest>::value, bool + !FmtTofmtTest>::value, bool > = true) { if (this->spec() != 's') { assert(false && "custom objects need '%s' format"); @@ -780,9 +757,9 @@ namespace detail { /* custom format case */ template Ptrdiff write(R &writer, bool, const T &val, - EnableIf>::value, bool + EnableIf>::value, bool > = true) { - FmtWriteRange sink(writer); + TostrRange sink(writer); if (!to_format(val, sink, *this)) return -1; return sink.get_written(); } @@ -793,7 +770,7 @@ namespace detail { !IsArithmetic::value && !IsConstructible::value && !FmtTostrTest::value && - !FmtTofmtTest>::value, bool + !FmtTofmtTest>::value, bool > = true) { assert(false && "value cannot be formatted"); return -1; diff --git a/ostd/string.hh b/ostd/string.hh index 3940daf..1be3d69 100644 --- a/ostd/string.hh +++ b/ostd/string.hh @@ -288,6 +288,7 @@ public: } ~StringBase() { + if (!p_cap) return; allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1); } @@ -686,14 +687,42 @@ String concat(std::initializer_list v, ConstCharRange sep = " ") { } namespace detail { - template + template + struct TostrRange: OutputRange, char> { + TostrRange() = delete; + TostrRange(R &out): p_out(out), p_written(0) {} + bool put(char v) { + bool ret = p_out.put(v); + p_written += ret; + return ret; + } + Size put_n(const char *v, Size n) { + Size ret = p_out.put_n(v, n); + p_written += ret; + return ret; + } + Size put_string(ConstCharRange r) { + return put_n(&r[0], r.size()); + } + Size get_written() const { return p_written; } + private: + R &p_out; + Size p_written; + }; + + template auto test_tostring(int) -> decltype(IsSame().to_string()), String>()); - template + + template + static True test_tostring(decltype(declval().to_string + (declval())) *); + + template False test_tostring(...); - template - using ToStringTest = decltype(test_tostring(0)); + template + using ToStringTest = decltype(test_tostring(0)); template True test_iterable(decltype(ostd::iter(declval())) *); @@ -724,12 +753,17 @@ struct ToString::value>> { }; template -struct ToString::value>> { +struct ToString>>::value +>> { using Argument = RemoveCv>; using Result = String; String operator()(const T &v) const { - return v.to_string(); + auto app = appender(); + detail::TostrRange> sink(app); + if (!v.to_string(sink)) return String(); + return move(app.get()); } };