Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -2512,42 +2512,53 @@ public:
}
}

private:
_NODISCARD static _CONSTEXPR20 size_type _Find_result_cast(const size_t _Off) noexcept {
if constexpr (sizeof(size_type) > sizeof(size_t)) { // only happens on 32-bit platforms with 64-bit size_type
if (_Off == static_cast<size_t>(-1)) {
return npos;
}
}
return static_cast<size_type>(_Off);
}

public:
#if _HAS_CXX17
template <class _StringViewIsh, _Is_string_view_ish<_StringViewIsh> = 0>
_NODISCARD _CONSTEXPR20 size_type find(const _StringViewIsh& _Right, const size_type _Off = 0) const
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for _Right beginning at or after _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type find(const basic_string& _Right, const size_type _Off = 0) const noexcept {
// look for _Right beginning at or after _Off
return static_cast<size_type>(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type find(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
const size_type _Count) const noexcept /* strengthened */ {
// look for [_Ptr, _Ptr + _Count) beginning at or after _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_find<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type find(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept
/* strengthened */ {
// look for [_Ptr, <null>) beginning at or after _Off
return static_cast<size_type>(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type find(const _Elem _Ch, const size_type _Off = 0) const noexcept {
// look for _Ch at or after _Off
return static_cast<size_type>(_Traits_find_ch<_Traits>(
return _Find_result_cast(_Traits_find_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand All @@ -2557,36 +2568,36 @@ public:
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for _Right beginning before _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type rfind(const basic_string& _Right, const size_type _Off = npos) const noexcept {
// look for _Right beginning before _Off
return static_cast<size_type>(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type rfind(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
const size_type _Count) const noexcept /* strengthened */ {
// look for [_Ptr, _Ptr + _Count) beginning before _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type rfind(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept
/* strengthened */ {
// look for [_Ptr, <null>) beginning before _Off
return static_cast<size_type>(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type rfind(const _Elem _Ch, const size_type _Off = npos) const noexcept {
// look for _Ch before _Off
return static_cast<size_type>(_Traits_rfind_ch<_Traits>(
return _Find_result_cast(_Traits_rfind_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand All @@ -2596,37 +2607,37 @@ public:
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for one of _Right at or after _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type find_first_of(
const basic_string& _Right, const size_type _Off = 0) const noexcept {
// look for one of _Right at or after _Off
return static_cast<size_type>(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
const size_type _Count) const noexcept /* strengthened */ {
// look for one of [_Ptr, _Ptr + _Count) at or after _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_of(
_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept /* strengthened */ {
// look for one of [_Ptr, <null>) at or after _Off
return static_cast<size_type>(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_of(const _Elem _Ch, const size_type _Off = 0) const noexcept {
// look for _Ch at or after _Off
return static_cast<size_type>(_Traits_find_ch<_Traits>(
return _Find_result_cast(_Traits_find_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand All @@ -2636,36 +2647,36 @@ public:
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for one of _Right before _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type find_last_of(const basic_string& _Right, size_type _Off = npos) const noexcept {
// look for one of _Right before _Off
return static_cast<size_type>(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
const size_type _Count) const noexcept /* strengthened */ {
// look for one of [_Ptr, _Ptr + _Count) before _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_of(
_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept /* strengthened */ {
// look for one of [_Ptr, <null>) before _Off
return static_cast<size_type>(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_of(const _Elem _Ch, const size_type _Off = npos) const noexcept {
// look for _Ch before _Off
return static_cast<size_type>(_Traits_rfind_ch<_Traits>(
return _Find_result_cast(_Traits_rfind_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand All @@ -2675,37 +2686,37 @@ public:
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for none of _Right at or after _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type find_first_not_of(
const basic_string& _Right, const size_type _Off = 0) const noexcept {
// look for none of _Right at or after _Off
return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_not_of(_In_reads_(_Count) const _Elem* const _Ptr,
const size_type _Off, const size_type _Count) const noexcept /* strengthened */ {
// look for none of [_Ptr, _Ptr + _Count) at or after _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_not_of(
_In_z_ const _Elem* const _Ptr, size_type _Off = 0) const noexcept /* strengthened */ {
// look for one of [_Ptr, <null>) at or after _Off
return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type find_first_not_of(const _Elem _Ch, const size_type _Off = 0) const noexcept {
// look for non-_Ch at or after _Off
return static_cast<size_type>(_Traits_find_not_ch<_Traits>(
return _Find_result_cast(_Traits_find_not_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand All @@ -2715,37 +2726,37 @@ public:
noexcept(_Is_nothrow_convertible_v<const _StringViewIsh&, basic_string_view<_Elem, _Traits>>) {
// look for none of _Right before _Off
basic_string_view<_Elem, _Traits> _As_view = _Right;
return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _As_view.data(), _As_view.size()));
}
#endif // _HAS_CXX17

_NODISCARD _CONSTEXPR20 size_type find_last_not_of(
const basic_string& _Right, const size_type _Off = npos) const noexcept {
// look for none of _Right before _Off
return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Right._Mypair._Myval2._Myptr(),
static_cast<size_t>(_Right._Mypair._Myval2._Mysize)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off,
const size_type _Count) const noexcept /* strengthened */ {
// look for none of [_Ptr, _Ptr + _Count) before _Off
return static_cast<size_type>(
return _Find_result_cast(
_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize),
static_cast<size_t>(_Off), _Ptr, static_cast<size_t>(_Count)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_not_of(
_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept /* strengthened */ {
// look for none of [_Ptr, <null>) before _Off
return static_cast<size_type>(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
return _Find_result_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(),
static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ptr, _Traits::length(_Ptr)));
}

_NODISCARD _CONSTEXPR20 size_type find_last_not_of(const _Elem _Ch, const size_type _Off = npos) const noexcept {
// look for non-_Ch before _Off
return static_cast<size_type>(_Traits_rfind_not_ch<_Traits>(
return _Find_result_cast(_Traits_rfind_not_ch<_Traits>(
_Mypair._Myval2._Myptr(), static_cast<size_t>(_Mypair._Myval2._Mysize), static_cast<size_t>(_Off), _Ch));
}

Expand Down
83 changes: 80 additions & 3 deletions tests/std/tests/GH_005546_containers_size_type_cast/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,10 +517,87 @@ CONSTEXPR20 bool test() {
return true;
}

#if _HAS_CXX20
static_assert(test());
#endif // _HAS_CXX20
template <typename T = char>
struct WideSizeAllocator {
using value_type = T;
using size_type = unsigned long long;

WideSizeAllocator() = default;

template <typename U>
constexpr WideSizeAllocator(const WideSizeAllocator<U>&) noexcept {}

constexpr T* allocate(size_type n) {
return allocator<T>{}.allocate(static_cast<size_t>(n));
}
constexpr void deallocate(T* p, size_type n) noexcept {
allocator<T>{}.deallocate(p, static_cast<size_t>(n));
}
};

CONSTEXPR20 bool test_LWG4259() {
// On 32-bit platforms, basic_string may use 64-bit size_type (depending on the allocator), while basic_string_view
// uses 32-bit size_t. This makes basic_string_view::npos smaller than basic_string::npos.
using WideSizeString = basic_string<char, char_traits<char>, WideSizeAllocator<char>>;

WideSizeString str = "Hello World";
WideSizeString not_found_str = "XYZ";
const char* not_found_cstr = "XYZ";
assert(str.find(not_found_str) == WideSizeString::npos);
assert(str.find(not_found_cstr, 0, 3) == WideSizeString::npos);
assert(str.find(not_found_cstr) == WideSizeString::npos);
assert(str.find('Z') == WideSizeString::npos);
#if _HAS_CXX17
string_view sv = "XYZ";
assert(str.find(sv) == WideSizeString::npos);
#endif
assert(str.rfind(not_found_str) == WideSizeString::npos);
assert(str.rfind(not_found_cstr, WideSizeString::npos, 3) == WideSizeString::npos);
assert(str.rfind(not_found_cstr) == WideSizeString::npos);
assert(str.rfind('Z') == WideSizeString::npos);
#if _HAS_CXX17
assert(str.rfind(sv) == WideSizeString::npos);
#endif
assert(str.find_first_of(not_found_str) == WideSizeString::npos);
assert(str.find_first_of(not_found_cstr, 0, 3) == WideSizeString::npos);
assert(str.find_first_of(not_found_cstr) == WideSizeString::npos);
assert(str.find_first_of('Z') == WideSizeString::npos);
#if _HAS_CXX17
assert(str.find_first_of(sv) == WideSizeString::npos);
#endif
WideSizeString all_in_str = "Hello World!";
WideSizeString search_all = "Hello World";
assert(search_all.find_first_not_of(all_in_str) == WideSizeString::npos);
assert(search_all.find_first_not_of("Hello World!", 0, 12) == WideSizeString::npos);
assert(search_all.find_first_not_of("Hello World!") == WideSizeString::npos);
WideSizeString repeated = "AAAAA";
assert(repeated.find_first_not_of('A') == WideSizeString::npos);
#if _HAS_CXX17
string_view sv_all = "Hello World!";
assert(search_all.find_first_not_of(sv_all) == WideSizeString::npos);
#endif
assert(str.find_last_of(not_found_str) == WideSizeString::npos);
assert(str.find_last_of(not_found_cstr, WideSizeString::npos, 3) == WideSizeString::npos);
assert(str.find_last_of(not_found_cstr) == WideSizeString::npos);
assert(str.find_last_of('Z') == WideSizeString::npos);
#if _HAS_CXX17
assert(str.find_last_of(sv) == WideSizeString::npos);
#endif
assert(search_all.find_last_not_of(all_in_str) == WideSizeString::npos);
assert(search_all.find_last_not_of("Hello World!", WideSizeString::npos, 12) == WideSizeString::npos);
assert(search_all.find_last_not_of("Hello World!") == WideSizeString::npos);
assert(repeated.find_last_not_of('A') == WideSizeString::npos);
#if _HAS_CXX17
assert(search_all.find_last_not_of(sv_all) == WideSizeString::npos);
#endif
return true;
}

int main() {
#if _HAS_CXX20
static_assert(test());
static_assert(test_LWG4259());
#endif // _HAS_CXX20
test();
test_LWG4259();
}