-
Notifications
You must be signed in to change notification settings - Fork 276
Enable using string views with wil::str_concat #590
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1836,6 +1836,28 @@ PCWSTR str_raw_ptr(const unique_any_t<T>& val) | |||||
| return str_raw_ptr(val.get()); | ||||||
| } | ||||||
|
|
||||||
| struct string_view_t | ||||||
| { | ||||||
| wchar_t const* data; | ||||||
| size_t length; | ||||||
| }; | ||||||
|
|
||||||
| inline string_view_t view_from_string(string_view_t const& s) | ||||||
| { | ||||||
| return s; | ||||||
| } | ||||||
|
|
||||||
| inline string_view_t view_from_string(PCWSTR str) | ||||||
| { | ||||||
| return string_view_t{str, str ? wcslen(str) : 0}; | ||||||
| } | ||||||
|
|
||||||
| template <typename T> | ||||||
| inline string_view_t view_from_string(wil::unique_any_t<T> const& str) | ||||||
| { | ||||||
| return view_from_string(str.get()); | ||||||
| } | ||||||
|
|
||||||
| #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) | ||||||
| /// @cond | ||||||
| namespace details | ||||||
|
|
@@ -1847,12 +1869,12 @@ namespace details | |||||
| // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present | ||||||
| // in the input buffer, it is overwritten. | ||||||
| template <typename string_type> | ||||||
| HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount) | ||||||
| HRESULT str_build_nothrow_(string_type& result, _In_reads_(strCount) string_view_t const* strList, size_t strCount) | ||||||
| { | ||||||
| size_t lengthRequiredWithoutNull{}; | ||||||
| for (auto& string : make_range(strList, strCount)) | ||||||
| { | ||||||
| lengthRequiredWithoutNull += string ? wcslen(string) : 0; | ||||||
| lengthRequiredWithoutNull += string.length; | ||||||
| } | ||||||
|
|
||||||
| details::string_maker<string_type> maker; | ||||||
|
|
@@ -1862,22 +1884,23 @@ namespace details | |||||
| auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; | ||||||
| for (auto& string : make_range(strList, strCount)) | ||||||
| { | ||||||
| if (string) | ||||||
| if (string.data) | ||||||
| { | ||||||
| RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); | ||||||
| RETURN_IF_FAILED(StringCchCopyNExW( | ||||||
| buffer, (bufferEnd - buffer), string.data, string.length, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| result = maker.release(); | ||||||
| return S_OK; | ||||||
| } | ||||||
|
|
||||||
| // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly | ||||||
| // NOTE: 'Strings' must all be string_view_t, or convertible to string_view_t, but C++ doesn't allow us to express that cleanly | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Second part's not really true anymore
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually... second part wasn't even true anymore before this |
||||||
| template <typename string_type, typename... Strings> | ||||||
| HRESULT str_build_nothrow(string_type& result, Strings... strings) | ||||||
| { | ||||||
| PCWSTR localStrings[] = {strings...}; | ||||||
| return str_build_nothrow(result, localStrings, sizeof...(Strings)); | ||||||
| string_view_t localStrings[] = {strings...}; | ||||||
| return str_build_nothrow_<string_type>(result, localStrings, ARRAYSIZE(localStrings)); | ||||||
| } | ||||||
| } // namespace details | ||||||
| /// @endcond | ||||||
|
|
@@ -1888,7 +1911,7 @@ template <typename string_type, typename... strings> | |||||
| HRESULT str_concat_nothrow(string_type& buffer, const strings&... str) | ||||||
| { | ||||||
| static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); | ||||||
| return details::str_build_nothrow(buffer, details::string_maker<string_type>::get(buffer), str_raw_ptr(str)...); | ||||||
| return details::str_build_nothrow(buffer, view_from_string(details::string_maker<string_type>::get(buffer)), view_from_string(str)...); | ||||||
| } | ||||||
| #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) | ||||||
|
|
||||||
|
|
@@ -4929,6 +4952,18 @@ inline PCWSTR str_raw_ptr(const unique_hstring& str) | |||||
| return str_raw_ptr(str.get()); | ||||||
| } | ||||||
|
|
||||||
| inline string_view_t view_from_string(HSTRING str) | ||||||
| { | ||||||
| UINT32 length = 0; | ||||||
| PCWSTR rawBuffer = WindowsGetStringRawBuffer(str, &length); | ||||||
| return string_view_t{rawBuffer, length}; | ||||||
| } | ||||||
|
|
||||||
| inline string_view_t view_from_string(const unique_hstring& str) | ||||||
| { | ||||||
| return view_from_string(str.get()); | ||||||
| } | ||||||
|
|
||||||
| #endif // __WIL__WINSTRING_H_ | ||||||
| #if (defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) | ||||||
| /// @cond | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,6 +132,16 @@ inline PCWSTR str_raw_ptr(const std::wstring& str) | |
| return str.c_str(); | ||
| } | ||
|
|
||
| inline string_view_t view_from_string(std::wstring_view const& s) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should get moved down to be inside the |
||
| { | ||
| return string_view_t{s.data(), s.length()}; | ||
| } | ||
|
|
||
| inline string_view_t view_from_string(std::wstring const& s) | ||
| { | ||
| return string_view_t{s.data(), s.length()}; | ||
| } | ||
|
|
||
| #if __cpp_lib_string_view >= 201606L | ||
| /** | ||
| zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty). | ||
|
|
@@ -241,6 +251,19 @@ class basic_zstring_view : public std::basic_string_view<TChar> | |
| using zstring_view = basic_zstring_view<char>; | ||
| using zwstring_view = basic_zstring_view<wchar_t>; | ||
|
|
||
| // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. | ||
| // This is the overload for std::wstring. Other overloads available in resource.h. | ||
| template <typename TChar> | ||
| inline auto str_raw_ptr(basic_zstring_view<TChar> str) | ||
| { | ||
| return str.c_str(); | ||
| } | ||
|
|
||
| inline string_view_t view_from_string(zwstring_view const& s) | ||
| { | ||
| return string_view_t{s.data(), s.length()}; | ||
| } | ||
|
|
||
| inline namespace literals | ||
| { | ||
| constexpr zstring_view operator""_zv(const char* str, std::size_t len) noexcept | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,12 +12,21 @@ | |
| // TODO: str_raw_ptr is not two-phase name lookup clean (https://github.com/Microsoft/wil/issues/8) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's been too long since I've last thought about this issue, but I wonder - if we're introducing a new function, is there's something we can do to fix this for [1] Function templates don't allow partial specialization and are therefore not suitable here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Side note: we can also maybe provide a specialization for Another possibility is to have detection logic in the base class template for something that is "string view like." E.g. something that has
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although it seems my memory is wrong... |
||
| namespace wil | ||
| { | ||
| struct string_view_t; | ||
|
|
||
| PCWSTR str_raw_ptr(HSTRING); | ||
| string_view_t view_from_string(HSTRING); | ||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| PCWSTR str_raw_ptr(const std::wstring&); | ||
| string_view_t view_from_string(std::wstring const&); | ||
| string_view_t view_from_string(std::wstring_view const&); | ||
| #endif | ||
| } // namespace wil | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| #include <wil/stl.h> | ||
| #endif | ||
|
|
||
| #include <wil/resource.h> | ||
| #include <wil/filesystem.h> | ||
|
|
||
|
|
@@ -528,6 +537,20 @@ TEST_CASE("FileSystemTests::VerifyStrConcat", "[filesystem]") | |
| REQUIRE_SUCCEEDED(wil::str_concat_nothrow(combinedStringNT, test2.c_str(), test3)); | ||
| REQUIRE(CompareStringOrdinal(combinedStringNT.get(), -1, expectedStr, -1, TRUE) == CSTR_EQUAL); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| SECTION("Concat with views of things") | ||
| { | ||
| auto part1 = std::wstring_view(L"Test2"); | ||
| auto part2 = std::wstring(L"Test3"); | ||
| auto part3 = wil::zwstring_view(L"Test4"); | ||
| auto part4 = wil::make_unique_string_nothrow<wil::unique_cotaskmem_string>(L"Test5"); | ||
| auto part5 = wil::make_unique_string_nothrow<wil::unique_hstring>(L"Test6"); | ||
| wil::unique_cotaskmem_string combinedStringNT = wil::make_unique_string_nothrow<wil::unique_cotaskmem_string>(L"Test1"); | ||
| REQUIRE_SUCCEEDED(wil::str_concat_nothrow(combinedStringNT, part1, part2, part3, part4, part5)); | ||
| REQUIRE(CompareStringOrdinal(combinedStringNT.get(), -1, L"Test1Test2Test3Test4Test5Test6", -1, TRUE) == CSTR_EQUAL); | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| TEST_CASE("FileSystemTests::VerifyStrPrintf", "[filesystem]") | ||
|
|
||
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.
Is the intent of this being "public" so that third parties can overload without touching the
detailsnamespace?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 suppose this is probably just following
str_raw_ptr. Searching fordef:str_raw_ptrin the OS tree yields no results outside of the WIL source code, so that might be enough to conclude that this doesn't necessarily need to be made public.