-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
include/fmt/format.h
Outdated
@@ -38,6 +38,7 @@ | |||
#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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
include/fmt/chrono.h
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
[do_]write(buffer<Char>& buf,
conflicts with write(OutputIt out
include/fmt/chrono.h
Outdated
constexpr size_t unit_buf_size = 32; | ||
code_unit unit_buf[unit_buf_size] = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because otherwise it has to be done by the callers effectively duplicating the logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general looks good, just a few more comments.
include/fmt/chrono.h
Outdated
}; | ||
|
||
template <typename CodeUnit> | ||
inline void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, let's leave as out parameter then.
include/fmt/chrono.h
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to replace write_char_buffer
with a function that takes string_view
instead of a buffer to avoid copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
include/fmt/chrono.h
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ecd81cf
to
608a9a3
Compare
Thank you! |
Replaced
std::basic_ostringstream
tostd::basic_ostream
withfmt::detail::formatbuf
.Benchmark: https://github.com/phprus/fmt-bench/tree/optimize-tm-formatting-6