-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Feature/complete module #2340
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
Feature/complete module #2340
Conversation
721829d to
929f2ba
Compare
| using detail::specs_handler; | ||
| using detail::to_unsigned; | ||
| using detail::type; | ||
| using detail::write; |
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'm still not sure, if this is really needed by the standard or if this is just an implementation deficit. At least it looks ugly.
From reading "C++ Templates - The Definitive Guide" and the standard, it is clear that the local class is a templated entity. I need further studies of the standard to find an answer to the question: which names within this so-called 'temploid' are bound at which time.
I'd rather prefer to make this 'temploid' a proper class template.
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.
Which local class are you referring to?
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.
struct format_handler within vformat_to in format.h, currently line 2649.
The problem is explored with this stripped-down code example here https://godbolt.org/z/34Ph9dee9. Fortunately I got this compiled with gcc (modules-branch) for the first time just a few minutes ago, so that I have a second opinion on the matter now: gcc doesn't require this 'symbolic-linking' of names into the body of vformat_to and all of my studies of the standard seem to corroborate that. Therefore I consider this an implementation bug in latest msvc. This symbolic linking is the only workaround that works at all. Qualified name lookup doesn't. And only local classes within function templates are affected.
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.
This is acknowledged as bug in msvc by realiable sources familiar with the compiler: name-binding is happening in phase 2 instead of phase 1 in this particular case. In other words: too late to find anything in namespace detail.
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.
Could you add a short comment clarifying that this is a workaround for an msvc bug?
929f2ba to
32af9f9
Compare
vitaut
left a comment
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.
In general looks good but i don't think we should be introducing a new header for macros because FMT_STRING and FMT_COMPILE are effectively obsolete with C++20. The former is redundant and the latter is replaced with a UDL.
include/fmt/compile.h
Outdated
| FMT_MODULE_EXPORT_BEGIN | ||
|
|
||
| // compile-time support | ||
| namespace ct { |
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 new namespace?
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.
This is stuff that was in namespace detail before. It must be made visible to be used from importers, f.e. by the ""_cf udl. The compiled_string tag class can be moved into namespace fmt just as well.
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 can't we make detail::compiled_string visible? It's an implementation detail and not supposed to be directly used by anyone, so detail is the correct namespace.
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.
If we make detail::compiled_string visible then the namespace detail becomes implicitly visible, too. This disenfranchises testing from ever checking if anything from that namespace becomes unwittingly visible that was never meant to be visible int the first place. This is the sole reason why I introduced namespace ct: everything in there is the sole minimum of non-public API that needs to be visible. I'd be sad if we'd call namespace detail "open season" to visibility. I was bugging Cameron to fix the current issue in msvc of detail being visible even if nothing in there is currently visible (he checked this with his BMI explorer tool) and he told me that this should be easy to fix. 🤞
I've just finished reworking the PR and peeked here to check for any news. Part of the rework was moving compiled_string to namespace fmt because I got the feeling you were objecting to putting it into ct where other necessarily visible compile-time related stuff is moved to as well. I will push the PR as it is now. Changing it in either direction is a piece of cake and can be done within a few minutes.
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.
Not making detail visible makes sense but ct looks like part of the public API which is undesirable. I suggest renaming ct to something like detail_exported to make it clear that this is an internal API but exported for module purposes.
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
| std::wstring w; | ||
| fmt::format_to(std::back_inserter(w), L"{}", 42); | ||
| EXPECT_EQ(L"42", w); | ||
|
|
||
| wchar_t wbuffer[4] = {0}; | ||
| fmt::format_to(wbuffer, L"{}", 42); | ||
| EXPECT_EQ(L"42", std::wstring_view(wbuffer)); | ||
|
|
||
| fmt::wmemory_buffer wb; | ||
| fmt::format_to(wb, L"{}", 42); | ||
| EXPECT_EQ(L"42", std::wstring_view(wbuffer)); |
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.
As before, I think this does too much functional testing. I suggest having a single wide format_to call.
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.
These are different overloads in the API. I think this is the minimal set for full coverage.
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.
OK, let's keep them.
test/module-test.cc
Outdated
| EXPECT_WRITE(stdout, fmt::print(L"{}µ", 42), as_string(L"42µ")); | ||
| EXPECT_WRITE(stderr, fmt::print(stderr, L"{}µ", 4.2), as_string(L"4.2µ")); |
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.
These can be problematic because IIRC they may fail if the stream is not in wide mode. I suggest only checking that this compiles without actually running, i.e. wrap in if (false).
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.
Ok, will do.
|
Even better then. I'm not keen on seeing macros in any API.
Both macros are listed in the documentation as official part of the API and this is why I felt like providing them. |
|
|
32af9f9 to
8f45f23
Compare
|
BTW, I've removed the block in my local repo that prevents msvc from running the |
include/fmt/compile.h
Outdated
| FMT_MODULE_EXPORT_BEGIN | ||
|
|
||
| // A compile-time string which is compiled into fast formatting code. | ||
| class compiled_string {}; |
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.
Does it still need to be public if we don't export the FMT_COMPILE macro and only provide a UDL?
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.
Well spotted - thanks!
All related stuff removed.
669e148 to
60cdb0e
Compare
include/fmt/compile.h
Outdated
|
|
||
| #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS | ||
| template <typename Char, size_t N, fixed_string<Char, N> Str> | ||
| template <typename Char, size_t N, fmt::detail_exported::str<Char, N> Str> |
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 suggest keeping the old name (fixed_string) which is more descriptive.
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.
Right.
My concern is the size of these fmt::v7::detail_exported::fixed_string linker symbols. This is just the common prefix. If you look at real code, the actual linker symbols with the specialized fixed strings become horribly long. May be I can convince Cameron to use a different mangling, may be derived from the base64-encoded SHA1 of the string value.
Anyway, I will change that.
60cdb0e to
8e7b4db
Compare
| // Converts a compile-time string to basic_string_view. | ||
| template <typename Char, size_t N> | ||
| constexpr auto string_to_view(const Char (&s)[N]) -> basic_string_view<Char> { | ||
| // Remove trailing NUL character if needed. Won't be present if this is used | ||
| // with a raw character array (i.e. not defined as a string). | ||
| return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; | ||
| } | ||
| template <typename Char> | ||
| constexpr auto string_to_view(detail::std_string_view<Char> s) | ||
| -> basic_string_view<Char> { | ||
| return {s.data(), s.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.
These are only used in macros that are not exported so probably should be in the detail namespace, not detail_exported. Also please keep the old names (compile_string_to_view).
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.
This is not correct. These overloads must be visible or xchar.h:231 will fail to compile. And there is no workaround for that.
I will change the name. Even though nothing is compiled here but just a view to the stored data created.
…on in module Make just the necessary parts available for lookup from client context.
8e7b4db to
1a351a2
Compare
|
Thank you! |
Add all missing pieces to complete {fmt} as module:
charoverloadsThis includes the macro-based API
FMT_STRINGandFMT_COMPILEby means of a module companion headerfmt.h