sink based concat() (no allocation in-func)

master
Daniel Kolesa 2015-07-23 02:04:54 +01:00
parent 287bdbd312
commit 7ede73f4dc
1 changed files with 54 additions and 52 deletions

View File

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