diff --git a/ostd/string.hh b/ostd/string.hh index 0368a58..d0d031f 100644 --- a/ostd/string.hh +++ b/ostd/string.hh @@ -623,66 +623,67 @@ inline namespace literals { inline namespace string_literals { } } } -template -AnyString concat(AllocatorArg, const A &alloc, const T &v, - ConstCharRange sep, F func) { - AnyString ret(alloc); +namespace detail { + template::value, + bool = IsConvertible::value> + struct ConcatPut; + + template + struct ConcatPut { + template + static bool put(R &sink, ConstCharRange v) { + return v.size() && (sink.put_n(&v[0], v.size()) == v.size()); + } + }; + + template + struct ConcatPut { + template + static bool put(R &sink, char v) { + return sink.put(v); + } + }; +} + +template +bool concat(R &&sink, const T &v, ConstCharRange sep, F func) { auto range = ostd::iter(v); - if (range.empty()) return ret; + if (range.empty()) return true; for (;;) { - ret += func(range.front()); + if (!detail::ConcatPut< + decltype(func(range.front())) + >::put(sink, func(range.front()))) + return false; range.pop_front(); if (range.empty()) break; - ret += sep; + sink.put_n(&sep[0], sep.size()); } - return ret; + return true; } -template -AnyString concat(AllocatorArg, const A &alloc, const T &v, - ConstCharRange sep = " ") { - AnyString ret(alloc); +template +bool concat(R &&sink, const T &v, ConstCharRange sep = " ") { auto range = ostd::iter(v); - if (range.empty()) return ret; + if (range.empty()) return true; for (;;) { - ret += range.front(); + ConstCharRange ret = range.front(); + if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size())) + return false; range.pop_front(); if (range.empty()) break; - ret += sep; + sink.put_n(&sep[0], sep.size()); } - return ret; + return true; } -template -String concat(const T &v, ConstCharRange sep, F func) { - return concat(allocator_arg, typename String::Allocator(), v, sep, func); +template +bool concat(R &&sink, std::initializer_list v, ConstCharRange sep, F func) { + return concat(sink, ostd::iter(v), sep, func); } -template -String concat(const T &v, ConstCharRange sep = " ") { - return concat(allocator_arg, typename String::Allocator(), v, sep); -} - -template -AnyString concat(AllocatorArg, const A &alloc, - std::initializer_list v, ConstCharRange sep, F func) { - return concat(allocator_arg, alloc, ostd::iter(v), sep, func); -} - -template -AnyString concat(AllocatorArg, const A &alloc, - std::initializer_list v, ConstCharRange sep = " ") { - return concat(allocator_arg, alloc, ostd::iter(v), sep); -} - -template -String concat(std::initializer_list v, ConstCharRange sep, F func) { - return concat(ostd::iter(v), sep, func); -} - -template -String concat(std::initializer_list v, ConstCharRange sep = " ") { - return concat(ostd::iter(v), sep); +template +String concat(R &&sink, std::initializer_list v, ConstCharRange sep = " ") { + return concat(sink, ostd::iter(v), sep); } namespace detail { @@ -710,18 +711,18 @@ namespace detail { }; template - auto test_tostring(int) -> - decltype(IsSame().to_string()), String>()); + auto test_stringify(int) -> + decltype(IsSame().stringify()), String>()); template - static True test_tostring(decltype(declval().to_string + static True test_stringify(decltype(declval().to_string (declval())) *); template - False test_tostring(...); + False test_stringify(...); template - using ToStringTest = decltype(test_tostring(0)); + using StringifyTest = decltype(test_stringify(0)); template True test_iterable(decltype(ostd::iter(declval())) *); @@ -741,11 +742,12 @@ struct ToString::value>> { String operator()(const T &v) const { String ret("{"); - ret += concat(ostd::iter(v), ", ", ToString< + auto x = appender(); + if (concat(x, ostd::iter(v), ", ", ToString< RemoveConst >> - >()); + >())) ret += x.get(); ret += "}"; return ret; } @@ -753,7 +755,7 @@ struct ToString::value>> { template struct ToString>>::value + detail::StringifyTest>>::value >> { using Argument = RemoveCv>; using Result = String;