Optimize tm formatting (Non C-locales and %Z) - #2617
Conversation
|
Thanks for the PR. I wonder why |
|
glibc and BSD libc has a |
|
@vitaut, New algorithm for |
ce6f4f2 to
16faf54
Compare
| #include <limits> // std::numeric_limits | ||
| #include <memory> // std::uninitialized_copy | ||
| #include <stdexcept> // std::runtime_error | ||
| #include <streambuf> // std::basic_streambuf |
There was a problem hiding this comment.
Adding a dependency on streambuf is undesirable esp. since formatbuf is not even used in format.h. Let's drop it by making formatbuf parameterized on streambuf.
| inline auto do_write(const std::tm& time, const std::locale& loc, char format, | ||
| char modifier) -> std::basic_string<Char> { | ||
| auto&& os = std::basic_ostringstream<Char>(); | ||
| inline void do_write(buffer<Char>& buf, const std::tm& time, |
There was a problem hiding this comment.
nit: I think we can drop do_ here and below because this prefix is only used in cases with identical signatures. Here signature is specific enough.
There was a problem hiding this comment.
Done.
[do_]write(buffer<Char>& buf, conflicts with write(OutputIt out
| constexpr size_t unit_buf_size = 32; | ||
| code_unit unit_buf[unit_buf_size] = {}; |
There was a problem hiding this comment.
Let's move buffer management to [do_]write_codecvt by making it return a struct, something like:
struct codecvt_result {
code_unit buf[32];
code_unit* end;
};There was a problem hiding this comment.
Why? write_codecvt does not depend on the the output buffer size. So I moved the buffer management out of write_codecvt.
There was a problem hiding this comment.
Because otherwise it has to be done by the callers effectively duplicating the logic.
There was a problem hiding this comment.
end value is dependent of buf.
Returning codecvt_result from a function corrupts end.
387d007 to
2cf2bd1
Compare
|
@vitaut, PR updated. |
|
Unexpected runtime error: https://github.com/phprus/fmt/runs/4412073708?check_suite_focus=true |
2cf2bd1 to
7a6fefc
Compare
7a6fefc to
ecd81cf
Compare
|
@vitaut, PR updated. Error on Windows is fixed. |
vitaut
left a comment
There was a problem hiding this comment.
In general looks good, just a few more comments.
| }; | ||
|
|
||
| template <typename CodeUnit> | ||
| inline void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf, |
There was a problem hiding this comment.
Why not return codecvt_result instead of passing it as an output parameter?
Also inline is probably not needed here.
There was a problem hiding this comment.
codecvt_result.end is depends on codecvt_result.buf
Returning codecvt_result from a function may result in codecvt_result being copied and end being corrupted.
It is possible to replace the pointer end with the length len, but this does not guarantee that there is no copying.
There was a problem hiding this comment.
Makes sense, let's leave as out parameter then.
| auto&& buf = basic_memory_buffer<Char>(); | ||
| buf.append(sv.begin(), sv.end()); | ||
| return write_char_buffer(out, buf, loc); |
There was a problem hiding this comment.
I think it's better to replace write_char_buffer with a function that takes string_view instead of a buffer to avoid copy.
| for (code_unit* p = buf; p != to_next; ++p) { | ||
| codecvt_result<code_unit> unit; | ||
| write_codecvt(unit, string_view(buf.data(), buf.size()), loc); | ||
| buf.clear(); |
There was a problem hiding this comment.
I think this function should use a new buffer instead of reusing the one passed externally. This will also allow to pass input as a string_view suggested below.
ecd81cf to
608a9a3
Compare
|
Thank you! |
Replaced
std::basic_ostringstreamtostd::basic_ostreamwithfmt::detail::formatbuf.Benchmark: https://github.com/phprus/fmt-bench/tree/optimize-tm-formatting-6