Skip to content
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

Untag dispatch find #2380

Merged
merged 27 commits into from
Jan 6, 2022
Merged
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d1c1d82
nested exception
AlexGuteniev Sep 27, 2021
b51d730
regex compare
AlexGuteniev Sep 27, 2021
b3095c4
polymorphic_allocator
AlexGuteniev Sep 27, 2021
56ff1ba
can use `_v` in polymorphic allocator
AlexGuteniev Sep 27, 2021
8169883
untag _Uses_allocator_piecewise more
AlexGuteniev Sep 27, 2021
96dc2d4
_Al
AlexGuteniev Sep 27, 2021
6d12638
ret type
AlexGuteniev Sep 27, 2021
0ccc226
Update stl/inc/regex
AlexGuteniev Sep 28, 2021
9ccdad1
Merge commit '6e669f092311fea66c6358efc1557c454a684fcc' into tag_disp…
AlexGuteniev Oct 20, 2021
d57e79e
Merge remote-tracking branch 'upstream/main' into tag_dispatch_2
AlexGuteniev Oct 20, 2021
d603670
_Within_limits
AlexGuteniev Oct 20, 2021
fb25b4a
@miscco review
AlexGuteniev Oct 20, 2021
4097134
sample
AlexGuteniev Oct 20, 2021
3554787
sample fix
AlexGuteniev Oct 20, 2021
c2b73bc
Pre is checked
AlexGuteniev Oct 20, 2021
00ead28
constexpr
AlexGuteniev Oct 20, 2021
104a592
is_permutation
AlexGuteniev Oct 28, 2021
7c83374
wrap everything
AlexGuteniev Oct 28, 2021
fdfa552
clang format
AlexGuteniev Oct 28, 2021
a62398d
_Find_unchecked
AlexGuteniev Dec 5, 2021
b6118b0
restore _Memchr_in_find_is_safe
AlexGuteniev Dec 5, 2021
9a9cc4b
restore _Memchr_in_find_is_safe missing param
AlexGuteniev Dec 5, 2021
d4c4d29
Merge branch 'tag_dispatch_2' into untag_dispatch_find
AlexGuteniev Dec 5, 2021
606f69f
Move comment.
StephanTLavavej Dec 10, 2021
ef3196c
Update stl/inc/xutility
AlexGuteniev Dec 10, 2021
31ae1ba
Merge remote-tracking branch 'upstream/main' into untag_dispatch_find
AlexGuteniev Dec 17, 2021
1e6fd4c
Document `_Within_limits` precondition right on the tin
CaseyCarter Dec 18, 2021
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
139 changes: 57 additions & 82 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -5081,61 +5081,45 @@ _NODISCARD constexpr auto lexicographical_compare_three_way(
}
#endif // __cpp_lib_concepts

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, true_type, _Any_tag, false_type) {
// signed _Elem, signed _Ty
return SCHAR_MIN <= _Val && _Val <= SCHAR_MAX;
}

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, false_type, true_type, false_type) {
// signed _Elem, unsigned _Ty, -1 == static_cast<_Ty>(-1)
return _Val <= SCHAR_MAX || static_cast<_Ty>(SCHAR_MIN) <= _Val;
}

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, true_type, false_type, false_type, false_type) {
// signed _Elem, unsigned _Ty, -1 != static_cast<_Ty>(-1)
return _Val <= SCHAR_MAX;
}

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, false_type, true_type, _Any_tag, false_type) {
// unsigned _Elem, signed _Ty
return 0 <= _Val && _Val <= UCHAR_MAX;
}

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, false_type, false_type, _Any_tag, false_type) {
// unsigned _Elem, unsigned _Ty
return _Val <= UCHAR_MAX;
}

template <class _Ty>
_NODISCARD constexpr bool _Within_limits(const _Ty& _Val, _Any_tag, _Any_tag, _Any_tag, true_type) {
// bool _Elem
return _Val == true || _Val == false;
}

template <class _InIt, class _Ty>
_NODISCARD constexpr bool _Within_limits(const _InIt&, const _Ty& _Val) {
// check whether _Val is within the limits of _Elem
using _Elem = _Iter_value_t<_InIt>;
return _Within_limits(_Val, bool_constant<is_signed_v<_Elem>>{}, bool_constant<is_signed_v<_Ty>>{},
bool_constant<-1 == static_cast<_Ty>(-1)>{}, bool_constant<is_same_v<_Elem, bool>>{});
}

template <class _InIt>
_NODISCARD constexpr bool _Within_limits(const _InIt&, const bool&) { // bools are always within the limits of _Elem
return true;
}

if constexpr (is_same_v<_Ty, bool>) {
return true;
}
#ifdef __cpp_lib_byte
template <class _InIt>
_NODISCARD constexpr bool _Within_limits(const _InIt&, const byte&) { // bytes are only comparable with other bytes
return true;
}
else if constexpr (is_same_v<_Ty, byte>) {
return true;
}
#endif // __cpp_lib_byte
else {
using _Elem = _Iter_value_t<_InIt>;
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
if constexpr (is_same_v<_Elem, bool>) {
return _Val == true || _Val == false;
} else if constexpr (is_signed_v<_Elem>) {
if (is_signed_v<_Ty>) {
AlexGuteniev marked this conversation as resolved.
Show resolved Hide resolved
// signed _Elem, signed _Ty
return SCHAR_MIN <= _Val && _Val <= SCHAR_MAX;
} else {
if constexpr (-1 == static_cast<_Ty>(-1)) {
// signed _Elem, unsigned _Ty, -1 == static_cast<_Ty>(-1)
return _Val <= SCHAR_MAX || static_cast<_Ty>(SCHAR_MIN) <= _Val;
} else {
// signed _Elem, unsigned _Ty, -1 != static_cast<_Ty>(-1)
return _Val <= SCHAR_MAX;
}
}
} else {
if constexpr (is_signed_v<_Ty>) {
// unsigned _Elem, signed _Ty
return 0 <= _Val && _Val <= UCHAR_MAX;
} else {
// unsigned _Elem, unsigned _Ty
return _Val <= UCHAR_MAX;
}
}
}
}

template <class _Iter, class _Ty>
_INLINE_VAR constexpr bool _Memchr_in_find_is_safe =
Expand All @@ -5148,8 +5132,29 @@ _INLINE_VAR constexpr bool _Memchr_in_find_is_safe =
> && !is_volatile_v<remove_reference_t<_Iter_ref_t<_Iter>>>;

template <class _InIt, class _Ty>
_NODISCARD constexpr _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_type) {
// find first matching _Val
_NODISCARD _CONSTEXPR20 _InIt _Find_unchecked(_InIt _First, const _InIt _Last, const _Ty& _Val) {
// find first matching _Val; choose optimization
// activate optimization for contiguous iterators to (const) bytes and integral values
// find first byte matching integral _Val
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
#if _HAS_CXX20
if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
{
if constexpr (_Memchr_in_find_is_safe<_InIt, _Ty>) {
if (!_Within_limits(_First, _Val)) {
return _Last;
}
Comment on lines +5151 to +5153
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested: I observe that originally, in C++20 when is_constant_evaluated() was true, we would perform the _Within_limits check and early return if possible. Now, when is_constant_evaluated() is true, we simply activate the classic algorithm fallback. This seems fine, since at most there would be a minor throughput improvement, and it seems fairly unusual for the _Within_limits check to actually be successful (when it isn't, we pay the cost of a branch).

That is, _Within_limits is necessary for the runtime memchr optimization, but it's not really valuable for the constexpr case, and the new code is organized accordingly. 😸

const auto _First_ptr = _To_address(_First);
const auto _Result = static_cast<remove_reference_t<_Iter_ref_t<_InIt>>*>(
_CSTD memchr(_First_ptr, static_cast<unsigned char>(_Val), static_cast<size_t>(_Last - _First)));
if constexpr (is_pointer_v<_InIt>) {
return _Result ? _Result : _Last;
} else {
return _Result ? _First + (_Result - _First_ptr) : _Last;
}
}
}

for (; _First != _Last; ++_First) {
if (*_First == _Val) {
break;
Expand All @@ -5159,36 +5164,6 @@ _NODISCARD constexpr _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, con
return _First;
}

template <class _InIt, class _Ty>
_NODISCARD _CONSTEXPR20 _InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, true_type) {
// find first byte matching integral _Val
if (!_Within_limits(_First, _Val)) {
return _Last;
}

#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
using _Elem = _Iter_value_t<_InIt>;
return _Find_unchecked1(_First, _Last, static_cast<_Elem>(_Val), false_type{});
}
#endif // _HAS_CXX20
const auto _First_ptr = _To_address(_First);
const auto _Result = static_cast<remove_reference_t<_Iter_ref_t<_InIt>>*>(
_CSTD memchr(_First_ptr, static_cast<unsigned char>(_Val), static_cast<size_t>(_Last - _First)));
if constexpr (is_pointer_v<_InIt>) {
return _Result ? _Result : _Last;
} else {
return _Result ? _First + (_Result - _First_ptr) : _Last;
}
}

template <class _InIt, class _Ty>
_NODISCARD _CONSTEXPR20 _InIt _Find_unchecked(const _InIt _First, const _InIt _Last, const _Ty& _Val) {
// find first matching _Val; choose optimization
// activate optimization for contiguous iterators to (const) bytes and integral values
return _Find_unchecked1(_First, _Last, _Val, bool_constant<_Memchr_in_find_is_safe<_InIt, _Ty>>{});
}

template <class _InIt, class _Ty>
_NODISCARD _CONSTEXPR20 _InIt find(_InIt _First, const _InIt _Last, const _Ty& _Val) { // find first matching _Val
_Adl_verify_range(_First, _Last);
Expand Down