forked from OctaForge/libostd
use a sink for to_string methods on objects (no extra allocs)
parent
9446470f3c
commit
ad2d69e83d
|
@ -595,29 +595,6 @@ namespace detail {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
struct FmtWriteRange: OutputRange<FmtWriteRange<R>, 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<typename T, typename R>
|
template<typename T, typename R>
|
||||||
static True test_tofmt(decltype(to_format(declval<const T &>(),
|
static True test_tofmt(decltype(to_format(declval<const T &>(),
|
||||||
declval<R &>(),
|
declval<R &>(),
|
||||||
|
@ -768,7 +745,7 @@ namespace detail {
|
||||||
!IsArithmetic<T>::value &&
|
!IsArithmetic<T>::value &&
|
||||||
!IsConstructible<ConstCharRange, const T &>::value &&
|
!IsConstructible<ConstCharRange, const T &>::value &&
|
||||||
FmtTostrTest<T>::value &&
|
FmtTostrTest<T>::value &&
|
||||||
!FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
|
!FmtTofmtTest<T, TostrRange<R>>::value, bool
|
||||||
> = true) {
|
> = true) {
|
||||||
if (this->spec() != 's') {
|
if (this->spec() != 's') {
|
||||||
assert(false && "custom objects need '%s' format");
|
assert(false && "custom objects need '%s' format");
|
||||||
|
@ -780,9 +757,9 @@ namespace detail {
|
||||||
/* custom format case */
|
/* custom format case */
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
Ptrdiff write(R &writer, bool, const T &val,
|
Ptrdiff write(R &writer, bool, const T &val,
|
||||||
EnableIf<FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
|
EnableIf<FmtTofmtTest<T, TostrRange<R>>::value, bool
|
||||||
> = true) {
|
> = true) {
|
||||||
FmtWriteRange<R> sink(writer);
|
TostrRange<R> sink(writer);
|
||||||
if (!to_format(val, sink, *this)) return -1;
|
if (!to_format(val, sink, *this)) return -1;
|
||||||
return sink.get_written();
|
return sink.get_written();
|
||||||
}
|
}
|
||||||
|
@ -793,7 +770,7 @@ namespace detail {
|
||||||
!IsArithmetic<T>::value &&
|
!IsArithmetic<T>::value &&
|
||||||
!IsConstructible<ConstCharRange, const T &>::value &&
|
!IsConstructible<ConstCharRange, const T &>::value &&
|
||||||
!FmtTostrTest<T>::value &&
|
!FmtTostrTest<T>::value &&
|
||||||
!FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
|
!FmtTofmtTest<T, TostrRange<R>>::value, bool
|
||||||
> = true) {
|
> = true) {
|
||||||
assert(false && "value cannot be formatted");
|
assert(false && "value cannot be formatted");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -288,6 +288,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
~StringBase() {
|
~StringBase() {
|
||||||
|
if (!p_cap) return;
|
||||||
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1);
|
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,14 +687,42 @@ String concat(std::initializer_list<T> v, ConstCharRange sep = " ") {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T>
|
template<typename R>
|
||||||
|
struct TostrRange: OutputRange<TostrRange<R>, 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<typename T, typename R>
|
||||||
auto test_tostring(int) ->
|
auto test_tostring(int) ->
|
||||||
decltype(IsSame<decltype(declval<T>().to_string()), String>());
|
decltype(IsSame<decltype(declval<T>().to_string()), String>());
|
||||||
template<typename>
|
|
||||||
|
template<typename T, typename R>
|
||||||
|
static True test_tostring(decltype(declval<const T &>().to_string
|
||||||
|
(declval<R &>())) *);
|
||||||
|
|
||||||
|
template<typename, typename>
|
||||||
False test_tostring(...);
|
False test_tostring(...);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename R>
|
||||||
using ToStringTest = decltype(test_tostring<T>(0));
|
using ToStringTest = decltype(test_tostring<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>())) *);
|
||||||
|
@ -724,12 +753,17 @@ struct ToString<T, EnableIf<detail::IterableTest<T>::value>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ToString<T, EnableIf<detail::ToStringTest<T>::value>> {
|
struct ToString<T, EnableIf<
|
||||||
|
detail::ToStringTest<T, detail::TostrRange<AppenderRange<String>>>::value
|
||||||
|
>> {
|
||||||
using Argument = RemoveCv<RemoveReference<T>>;
|
using Argument = RemoveCv<RemoveReference<T>>;
|
||||||
using Result = String;
|
using Result = String;
|
||||||
|
|
||||||
String operator()(const T &v) const {
|
String operator()(const T &v) const {
|
||||||
return v.to_string();
|
auto app = appender<String>();
|
||||||
|
detail::TostrRange<AppenderRange<String>> sink(app);
|
||||||
|
if (!v.to_string(sink)) return String();
|
||||||
|
return move(app.get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue