-
Notifications
You must be signed in to change notification settings - Fork 39
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
Refactored starts_with and ends_with #259
Conversation
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.
clang-tidy
in the new code
clang-format
found formatting issues in the code submitted.:warning:
Make sure to run clang-format and update this pull request.
(1/1)
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.
clang-tidy
in the new code
clang-format
found formatting issues in the code submitted.:warning:
Make sure to run clang-format and update this pull request.
(1/1)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
ASSERT_TRUE(starts_with(L"Ubuntu 22.04.1 LTS", L"Ubuntu")); | ||
ASSERT_TRUE(ends_with(L"Ubuntu 22.04.1 LTS", L"LTS")); | ||
const std::wstring test_str{L"Ubuntu 22.04.1 LTS"}; | ||
ASSERT_TRUE(ends_with(test_str, L"LTS")); |
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.
Supporting heterogeneous string-like entities is a great thing! :D
@@ -63,4 +96,4 @@ TEST(UpgradePolicyTests, Concat) | |||
std::filesystem::path example_file{L"/home/fox/documents/example.json"}; | |||
auto with_path = concat(L"diff ", example_file, L" ", example_file.wstring()); // Only first one to be quoted | |||
ASSERT_EQ(with_path, LR"(diff "/home/fox/documents/example.json" /home/fox/documents/example.json)"); | |||
} | |||
} |
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.
That remove-newline-at-eof-thingy is really annoying. We'll soon need to implement a way to avoid it.
{ | ||
return std::is_same_v<T, char> || std::is_same_v<T, wchar_t> || std::is_same_v<T, signed char> || | ||
std::is_same_v<T, unsigned char> || std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t>; | ||
// C++20 introduces char8_t |
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.
Did you consider checking if there is a specialization of std::char_traits<T>::char_type
to avoid such chain of is_same_v
and get it automatically up-to-date with the standard library version in use?
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 could use something like:
template <typename CharT>
constexpr bool is_character() {
// We know for sure double won't have a char_traits specialization.
using default_type = std::char_traits<double>::int_type;
return !std::is_same_v<std::char_traits<CharT>::int_type, default_type>;
}
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 played around for a while. Signed and unsigned characters fail the test:
https://godbolt.org/z/M17csTEc1
I also tried using an empty struct instead of double but it also has long
as its integer type. I understand that is the default value.
The concatenated is_same_v
s is not pretty but it has going for it that it's very transparent as to how it works.
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 like it better than the previous alternative!
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.
One minor technical issue.
DistroLauncher/algorithms.h
Outdated
return value; | ||
} | ||
|
||
template <std::size_t Size, typename T> constexpr auto view_adaptor(const T value[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.
The array will always decay into a pointer, thus this case is never instantiated, which seems to be actually fine, otherwise this would be a bug:
const std::string tested{"Ubuntu 22.04 LTS"};
const char sub[7] = "Ubuntu"; //6 chars + \0.
// would fail because `std::basic_string_view<const char>(sub, 7);` would forcebly include the '\0' in the view, then `mismatch.first` would be an iterator to the last char, not the one-after-last.
ASSERT_TRUE(starts_with(tested, sub));
If you comment out the pointer specialization you'll see errors due the '\0' being included in the string_view due the array specialization.
I think this must be removed.
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 on purpose. char
-like types decay to a pointer which is what we want, but non-chars don't see the declaration of the pointer version (due to the enable_if
) and hence stay as c-arrays. I can explicitly disable it for char
-like types, though.
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, now pointer decay is only enabled for chars; and c-array is only enabled for non-chars:
template<typename T>
enable_if_t<!is_character<T>(), basic_string_view<T>> view_adaptor(const T value[Size]);
template<typename CharT>
enable_if_t<is_character<CharT>(), basic_string_view<CharT>> view_adaptor(const CharT* value);
The need for concepts strikes once again 😓
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 taking that work!
Abstract
Removed the need to add braces around string literals in
starts_with
andends_with
:Explanation
The main issue is that
std::end(const char*)
points to the entry after the null termination, making naive implementations fail. This can be solved using string_views. Then template parameter deduction starts behaving funny. This is solved here with a helper adaptor template that does the following type conversions, in this order:const CharT* -> basic_string_view<CharT>
: SFINAE'd to work only with chars. Null-termination expected.const T[N] -> basic_string_view<T>
: SFINAE'd to work for non-characters only. No null-termination.const T& -> const T&
: Any other containers stay as they were.Comparing
char
andwchar_t
(or any other combination of diferent chars) stays forbidden, now with a static assert instead of template resolution falure.Side benefits
These were not the goal but it's nice to have them
starts_with
andends_with
now use the same implementationstarts_with_impl
, simply switching between forward and reverse iterators.