-
Notifications
You must be signed in to change notification settings - Fork 380
Add string_view API for c++17 #410
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
base: master
Are you sure you want to change the base?
Conversation
#error "string_view gets auto-detected" | ||
#endif | ||
|
||
// clang-format off |
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.
Disabling clang-format as settings will flatten everything which makes this hard to follow.
Using normal feature detection for compilers supporting it. Feature detection was also noted in the WIP PR.
Tested paths on godbolt.org as I don't have access to all the compiler versions.
Idea is that if string_view is supported, we should support it.
src/cxx.cc
Outdated
@@ -65,7 +65,11 @@ static void initString(String *self, const char *s, size_t len) { | |||
} | |||
} | |||
|
|||
#ifdef CXXBRIDGE_HAS_STRING_VIEW | |||
String::String(std::string_view sv) : String(sv.data(), sv.length()) {} |
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.
Forwarding it to ptr/len ctor that does the nice asserts.
FYI, empty string_view has nullptr and 0 size.
@@ -14,6 +14,45 @@ | |||
#include <basetsd.h> | |||
#endif | |||
|
|||
#ifdef CXXBRIDGE_HAS_STRING_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.
Using CXXBRIDGE_.. naming to align more with other defines. WIP used CXX_... naming
Bikeshedding time?
tests/ffi/tests.cc
Outdated
@@ -598,9 +598,26 @@ extern "C" const char *cxx_run_test() noexcept { | |||
r_take_unique_ptr(std::unique_ptr<C>(new C{2020})); | |||
r_take_ref_c(C{2020}); | |||
r_take_str(rust::Str("2020")); | |||
r_take_empty_str(rust::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.
Added "empty" tests for std::string_view
and figured we might as well add tests for rust::str
and rust::String
#else | ||
// no __has_include | ||
#if _MSC_VER >= 1910L && _MSVC_LANG > 201402L | ||
// msvc: 19.10 requires c++latest (!) |
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.
Older msvc compilers that supported string_view. Not sure what compiler versions you want to support, but I've included the ones I could get my hands on through godbolt.
There could be a discussion if it would make sense to support "c++latest" in cxx as a feature (for msvc).
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! This is great. I am going to defer reviewing this for a little bit while I get the https://cxx.rs site wrapped up and published. That will also provide a better place to document the features situation -- I think it's not good for a readme to go into this level of detail.
d3eb663
to
18d9c71
Compare
No pressure to look at this. Just had some downtime at work to quickly run after this. Rebased changes and I've moved the "features" documentation into the book/build/cargo.md. Not sure if you want to have it there or somewhere else. Just a placeholder, really. |
@@ -144,6 +144,46 @@ manifest key][links]* in the Cargo reference. | |||
|
|||
[links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key | |||
|
|||
## Features |
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 sure if that's the place where you'd want to document features if at all. Just a placeholder.
Nicer to look at page: https://github.com/roligugus/cxx/blob/string_view/book/src/build/cargo.md#features
tests/ffi/tests.cc
Outdated
r_take_rust_string(std::string_view("2020")); | ||
r_take_empty_rust_string(std::string_view{}); | ||
r_take_empty_rust_string(std::string_view("")); | ||
const auto rustString = rust::String("2020"); // avoid lifetime issue |
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.
What lifetime issue is this comment 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.
"Lifetime issue" was referring to lifetime of (temporary) rust::String("2020")
needing to exceed lifetime of string_view
in ASSERT() below.
Was easier to use defensive programming than trying to figure it out exactly. Anyhow, checked and the temporary rust::String("2020")
is only destructed after the comparison.
Will remove this var and merge code into ASSERT().
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 am concerned that in this implementation, simply adding a new dependency to a Cargo build graph can cause existing working code to fail to link. If the newly added crates somewhere contain a dependency on "cxx/c++17", that leads to removing various symbols from the cxx rlib without doing anything to eliminate use of those symbols in elsewhere in the build graph.
Relatedly it seems like this implementation violates ODR which is UB (https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule), because the class definitions of Str and String don't necessarily "consists of the same sequence of tokens" each place they appear.
Thoughts? It seems like more design work is still required on how to integrate this from the build side.
Yes, that is a downside of tying that functionality to a C++ standard switch and automatically enabling it in the header if it's available while at the same time removing existing functionality. The nice thing is that you get link errors due to missing symbols that your particular client compilation requires. UPDATE: Removed paragraph as I think I understood wrongly what you meant. The other stuff here still applies, imho. The current approach would not work for these cases as it breaks the cxx lib ABI as well as the API. In order to always be able to handle this case, one must never remove current functionality to be backwards compatible from an ABI point-of-view. One could be somewhat flexible with APIs depending on the change - more on that later. Yeah, there's also the "let's version APIs and lib" approach that one would do in C++/C land (not sure about rust), but I don't think that worth considering as that's always a pain and I typically like avoiding that like the pest. Possible approach to follow... |
Don't think this is an ODR problem in this instance. The cxx rlib itself is fine if compiled e.g. with C++17. No ODR there. Your client code is also fine even though your included cxx header might declare different things. No ODR there. However, you will run into link errors when trying to link the cxx rlib into your client lib/exec conveniently avoiding ODR. It only would become an ODR issue if you were compiling cxx and your client TUs directly into the same executable or lib without going through a separate cxx lib. However, in that case you will be using your own build system and you better be compiling everything linked together into the same lib/exec using the same compilation settings. |
Agree. So what can we do to avoid that? The problem is that this PR breaks the API and the ABI by adding a new A way of handling that is not to automatically enable the The only way to handle that would be to do something similar to what e.g. autotools do. The idea is to bake the functionality into cxx. E.g. have the cxx crate write a However, you still would run into the same issue for breaking changes where client A needs cxx features X and client B needs cxx feature Y. So that would not be solved as the cxx lib compilation would define the supported functionality depending on the features defined. A better way to fix that for this change is to "only add new APIs". Since we're currently keeping the #ifdef CXXBRIDGE_HAS_STRING_VIEW
String(std::string_view);
#endif
String(const std::string &);
String(const char *);
String(const char *, size_t); Ditto with the conversion operator. This will keep the ABI backwards-compatible, i.e. client code compiled with e.g. c++14 will be able to compile and link against a cxx rlib compiled with c++17. This allows to compile the cxx lib with whatever highest c++ standard required to support both c++14 (using We can go further than that. By inlining the new We can keep the automatic enabling of the string_view ctor and conversion operators to support Sounds like a better approach? I can update this PR to give a better picture. |
18d9c71
to
e135131
Compare
<tr><td>c++17</td><td>-std=c++17 (gcc, clang), /std:c++17 (msvc)</td><td>Compile CXX lib with c++17</td></tr> | ||
</table> | ||
|
||
## Additional C++ standard features |
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.
Potential documentation for enabling additional C++ APIs.
Nicer to look at page:
https://github.com/roligugus/cxx/blob/string_view/book/src/build/cargo.md#additional-c-standard-features
@@ -34,6 +73,9 @@ class String final { | |||
String(String &&) noexcept; | |||
~String() noexcept; | |||
|
|||
#ifdef CXXBRIDGE_HAS_STRING_VIEW | |||
String(std::string_view sv) : String(sv.data(), sv.length()) {} |
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.
We should add "always inline", e.g. __attribute__((always_inline))
(gcc/clang) and __forceinline
(msvc), to make sure it gets inlined even if e.g. people disable inlining, etc.
Hi there! I went looking for this feature earlier today, seems like it's stalled out. Is there any interest in revisiting this? |
Follow-up of WIP: #80 to add
std::string_view
support.std::string_view
is enabled if cxx is compiled with c++17 or later. One will need to set the c++17 (or later) feature on the cxx crate for cargo-based builds. Also added a "CXX Features" section to the cargo build info if that helps.Notes:
rust::str
andrust::String
parameters and return values in the client code. Not sure you'd want to break the API.tests/ffi/Cargo.toml
at this time. Not ideal, but a start.