Skip to content

Commit

Permalink
Fix #94 and remove compiler bug workarounds. (#175)
Browse files Browse the repository at this point in the history
* Properly comment "Tukey's ninther".

* Remove workarounds for VSO-946746.

VSO-946746 "conditional explicit(bool) doesn't work with /clr:pure"
was fixed on 2019-07-23, and should be available in
VS 2019 16.4 Preview 1.

* Remove workarounds for VSO-433486.

VSO-433486 "_Count / 2 inside while (0 < _Count) loop is not
transformed into a simple shift" was fixed on 2019-08-27
and should be available in VS 2019 16.4 Preview 2.

Some shifts are still necessary, and are now commented.

* This mirrors a Microsoft-internal PR:
https://devdiv.visualstudio.com/DevDiv/_git/msvc/pullrequest/207988
  • Loading branch information
StephanTLavavej committed Oct 15, 2019
1 parent 6aa3b02 commit 53cdb9f
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 56 deletions.
69 changes: 37 additions & 32 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ _NODISCARD _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
const auto _ULast = _Get_unwrapped(_Last);
auto _Count = _STD distance(_UFirst, _ULast);
while (0 < _Count) { // divide and conquer, find half that contains answer
const auto _Count2 = static_cast<_Iter_diff_t<_FwdIt>>(_Count >> 1);
const auto _Count2 = static_cast<_Iter_diff_t<_FwdIt>>(_Count / 2);
const auto _UMid = _STD next(_UFirst, _Count2);

if (_Pred(*_UMid)) { // try top half
Expand Down Expand Up @@ -2619,9 +2619,10 @@ _BidIt stable_partition(_ExPo&&, _BidIt _First, _BidIt _Last, _Pr _Pred) noexcep
template <class _RanIt, class _Ty, class _Pr>
void _Push_heap_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) {
// percolate _Hole to _Top or where _Val belongs, using _Pred
for (_Iter_diff_t<_RanIt> _Idx = (_Hole - 1) >> 1; // TRANSITION, VSO-433486
_Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val);
_Idx = (_Hole - 1) >> 1) { // TRANSITION, VSO-433486
using _Diff = _Iter_diff_t<_RanIt>;
for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen
_Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); //
_Idx = (_Hole - 1) >> 1) { // shift for codegen
// move _Hole up to parent
*(_First + _Hole) = _STD move(*(_First + _Idx));
_Hole = _Idx;
Expand Down Expand Up @@ -2660,7 +2661,7 @@ void _Pop_heap_hole_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_di

// Check whether _Idx can have a child before calculating that child's index, since
// calculating the child's index can trigger integer overflows
const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // TRANSITION, VSO-433486
const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen
while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child
_Idx = 2 * _Idx + 2;
if (_DEBUG_LT_PRED(_Pred, *(_First + _Idx), *(_First + (_Idx - 1)))) {
Expand All @@ -2683,9 +2684,9 @@ void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _
// pop *_First to *_Dest and reheap, using _Pred
// precondition: _First != _Last
// precondition: _First != _Dest
*_Dest = _STD move(*_First);
_Pop_heap_hole_by_index(
_First, _Iter_diff_t<_RanIt>(0), _Iter_diff_t<_RanIt>(_Last - _First), _STD move(_Val), _Pred);
*_Dest = _STD move(*_First);
using _Diff = _Iter_diff_t<_RanIt>;
_Pop_heap_hole_by_index(_First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD move(_Val), _Pred);
}

template <class _RanIt, class _Pr>
Expand Down Expand Up @@ -2713,8 +2714,9 @@ void pop_heap(_RanIt _First, _RanIt _Last) { // pop *_First to *(_Last - 1) and
template <class _RanIt, class _Pr>
void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
// make nontrivial [_First, _Last) into a heap, using _Pred
_Iter_diff_t<_RanIt> _Bottom = _Last - _First;
for (_Iter_diff_t<_RanIt> _Hole = _Bottom >> 1; 0 < _Hole;) { // TRANSITION, VSO-433486
using _Diff = _Iter_diff_t<_RanIt>;
_Diff _Bottom = _Last - _First;
for (_Diff _Hole = _Bottom >> 1; 0 < _Hole;) { // shift for codegen
// reheap top half, bottom to top
--_Hole;
_Iter_value_t<_RanIt> _Val = _STD move(*(_First + _Hole));
Expand All @@ -2737,9 +2739,10 @@ void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a hea
template <class _RanIt, class _Pr>
_RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
// find extent of range that is a heap ordered by _Pred
const _Iter_diff_t<_RanIt> _Size = _Last - _First;
for (_Iter_diff_t<_RanIt> _Off = 1; _Off < _Size; ++_Off) {
if (_DEBUG_LT_PRED(_Pred, _First[(_Off - 1) >> 1], _First[_Off])) { // TRANSITION, VSO-433486
using _Diff = _Iter_diff_t<_RanIt>;
const _Diff _Size = _Last - _First;
for (_Diff _Off = 1; _Off < _Size; ++_Off) {
if (_DEBUG_LT_PRED(_Pred, _First[(_Off - 1) >> 1], _First[_Off])) { // shift for codegen
return _First + _Off;
}
}
Expand Down Expand Up @@ -2840,7 +2843,7 @@ _NODISCARD _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr
_Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _Get_unwrapped(_Last));

while (0 < _Count) { // divide and conquer, find half that contains answer
_Iter_diff_t<_FwdIt> _Count2 = _Count >> 1; // TRANSITION, VSO-433486
_Iter_diff_t<_FwdIt> _Count2 = _Count / 2;
const auto _UMid = _STD next(_UFirst, _Count2);
if (_Pred(_Val, *_UMid)) {
_Count = _Count2;
Expand Down Expand Up @@ -2878,7 +2881,7 @@ _NODISCARD pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _
break;
}

_Diff _Count2 = _Count >> 1; // TRANSITION, VSO-433486
_Diff _Count2 = _Count / 2;
const auto _UMid = _STD next(_UFirst, _Count2);
if (_DEBUG_LT_PRED(_Pred, *_UMid, _Val)) { // range begins above _UMid, loop
_UFirst = _Next_iter(_UMid);
Expand Down Expand Up @@ -3172,16 +3175,17 @@ void _Buffered_inplace_merge_divide_and_conquer(_BidIt _First, _BidIt _Mid, _Bid
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred) {
// merge sorted [_First, _Mid) with sorted [_Mid, _Last), using _Pred
// usual invariants apply
using _Diff = _Iter_diff_t<_BidIt>;
if (_Count1 <= _Count2) {
const _Iter_diff_t<_BidIt> _Count1n = _Count1 >> 1; // TRANSITION, VSO-433486
const _BidIt _Firstn = _STD next(_First, _Count1n);
const _BidIt _Lastn = _STD lower_bound(_Mid, _Last, *_Firstn, _Pred);
const _Diff _Count1n = _Count1 >> 1; // shift for codegen
const _BidIt _Firstn = _STD next(_First, _Count1n);
const _BidIt _Lastn = _STD lower_bound(_Mid, _Last, *_Firstn, _Pred);
_Buffered_inplace_merge_divide_and_conquer2(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred,
_Firstn, _Lastn, _Count1n, _STD distance(_Mid, _Lastn));
} else {
const _Iter_diff_t<_BidIt> _Count2n = _Count2 >> 1; // TRANSITION, VSO-433486
const _BidIt _Lastn = _STD next(_Mid, _Count2n);
const _BidIt _Firstn = _STD upper_bound(_First, _Mid, *_Lastn, _Pred);
const _Diff _Count2n = _Count2 >> 1; // shift for codegen
const _BidIt _Lastn = _STD next(_Mid, _Count2n);
const _BidIt _Firstn = _STD upper_bound(_First, _Mid, *_Lastn, _Pred);
_Buffered_inplace_merge_divide_and_conquer2(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred,
_Firstn, _Lastn, _STD distance(_First, _Firstn), _Count2n);
}
Expand Down Expand Up @@ -3283,13 +3287,14 @@ void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred) {

++_ULast;

const _Iter_diff_t<_BidIt> _Count1 = _STD distance(_UFirst, _UMid);
using _Diff = _Iter_diff_t<_BidIt>;
const _Diff _Count1 = _STD distance(_UFirst, _UMid);
if (_Count1 == 1) { // rotate only element remaining in left partition to the end, without allocating
_Rotate_one_left(_UFirst, _UMid, _ULast);
return;
}

const _Iter_diff_t<_BidIt> _Count2 = _STD distance(_UMid, _ULast);
const _Diff _Count2 = _STD distance(_UMid, _ULast);
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Min_value(_Count1, _Count2)};
_Buffered_inplace_merge_unchecked_impl(
_UFirst, _UMid, _ULast, _Count1, _Count2, _Temp_buf._Data, _Temp_buf._Capacity, _Pass_fn(_Pred));
Expand Down Expand Up @@ -3361,7 +3366,7 @@ template <class _RanIt, class _Pr>
void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { // sort median element to middle
using _Diff = _Iter_diff_t<_RanIt>;
const _Diff _Count = _Last - _First;
if (40 < _Count) { // median of nine
if (40 < _Count) { // Tukey's ninther
const _Diff _Step = (_Count + 1) >> 3; // +1 can't overflow because range was made inclusive in caller
const _Diff _Two_step = _Step << 1; // note: intentionally discards low-order bit
_Med3_unchecked(_First, _First + _Step, _First + _Two_step, _Pred);
Expand All @@ -3376,7 +3381,7 @@ void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred
template <class _RanIt, class _Pr>
pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
// partition [_First, _Last), using _Pred
_RanIt _Mid = _First + ((_Last - _First) >> 1); // TRANSITION, VSO-433486
_RanIt _Mid = _First + ((_Last - _First) >> 1); // shift for codegen
_Guess_median_unchecked(_First, _Mid, _Last - 1, _Pred);
_RanIt _Pfirst = _Mid;
_RanIt _Plast = _Pfirst + 1;
Expand Down Expand Up @@ -3446,8 +3451,8 @@ void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _
_Iter_diff_t<_RanIt> _Count;
while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) { // divide and conquer by quicksort
auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
// TRANSITION, VSO-433486
_Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions

_Ideal = _Ideal / 2 + _Ideal / 4; // allow 1.5 log2(N) divisions

if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
_Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
Expand Down Expand Up @@ -3635,7 +3640,7 @@ void _Stable_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter
if (_Count <= _ISORT_MAX) {
_Insertion_sort_unchecked(_First, _Last, _Pred); // small
} else { // sort halves and merge
const auto _Half_count = static_cast<_Diff>(_Count >> 1);
const auto _Half_count = static_cast<_Diff>(_Count / 2);
const auto _Half_count_ceil = static_cast<_Diff>(_Count - _Half_count);
const _BidIt _Mid = _STD next(_First, _Half_count_ceil);
if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer
Expand Down Expand Up @@ -3666,7 +3671,7 @@ void stable_sort(const _BidIt _First, const _BidIt _Last, _Pr _Pred) {
return;
}

_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Count - (_Count >> 1)};
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Count - _Count / 2};
_Stable_sort_unchecked(_UFirst, _ULast, _Count, _Temp_buf._Data, _Temp_buf._Capacity, _Pass_fn(_Pred));
}

Expand Down Expand Up @@ -3754,9 +3759,9 @@ _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _La
for (; _UFirst1 != _ULast1; ++_UFirst1) {
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) {
// replace top with new largest:
_Pop_heap_hole_by_index(_UFirst2, static_cast<_Iter_diff_t<_RanIt>>(0),
static_cast<_Iter_diff_t<_RanIt>>(_UMid2 - _UFirst2), static_cast<_Iter_value_t<_InIt>>(*_UFirst1),
_Pass_fn(_Pred));
using _Diff = _Iter_diff_t<_RanIt>;
_Pop_heap_hole_by_index(_UFirst2, static_cast<_Diff>(0), static_cast<_Diff>(_UMid2 - _UFirst2),
static_cast<_Iter_value_t<_InIt>>(*_UFirst1), _Pass_fn(_Pred));
}
}

Expand Down
2 changes: 1 addition & 1 deletion stl/inc/charconv
Original file line number Diff line number Diff line change
Expand Up @@ -2514,7 +2514,7 @@ template <typename UInt, typename Pred>
assert(first <= last);

for (UInt n = last - first; n > 0;) {
const UInt n2 = n >> 1;
const UInt n2 = n / 2;
const UInt mid = first + n2;

if (pred(mid)) {
Expand Down
9 changes: 4 additions & 5 deletions stl/inc/execution
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ constexpr size_t _Get_least2_chunked_work_chunk_count(const size_t _Hw_threads,
// get the number of chunks to break work into to parallelize, assuming chunks must be of size 2
const auto _Size_count = static_cast<size_t>(_Count); // no overflow due to forward iterators
// we assume _Hw_threads * _Oversubscription_multiplier does not overflow
return _Get_chunked_work_chunk_count(_Hw_threads, _Size_count >> 1);
return _Get_chunked_work_chunk_count(_Hw_threads, _Size_count / 2);
}

// STRUCT TEMPLATE _Parallelism_allocator
Expand Down Expand Up @@ -2679,7 +2679,7 @@ bool _Process_sort_work_item(const _RanIt _Basis, _Pr _Pred, _Sort_work_item<_Ra

if (0 < _Ideal) { // divide and conquer by partitioning (quicksort)
const auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
const auto _New_ideal = static_cast<_Diff>((_Ideal >> 1) + (_Ideal >> 2)); // allow 1.5 log2(N) divisions
const auto _New_ideal = static_cast<_Diff>(_Ideal / 2 + _Ideal / 4); // allow 1.5 log2(N) divisions
_Wi._Size = _Mid.first - _First;
_Wi._Ideal = _New_ideal;
_Right_fork_wi = {_Mid.second - _Basis, _Last - _Mid.second, _New_ideal};
Expand Down Expand Up @@ -3030,8 +3030,7 @@ void stable_sort(_ExPo&&, const _BidIt _First, const _BidIt _Last, _Pr _Pred) no
_Attempt_parallelism = false;
}

_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{
_Attempt_parallelism ? _Count : _Count - (_Count >> 1)};
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Attempt_parallelism ? _Count : _Count - _Count / 2};
if constexpr (remove_reference_t<_ExPo>::_Parallelize) {
if (_Attempt_parallelism) {
// forward+ iterator overflow assumption for size_t cast
Expand Down Expand Up @@ -3283,7 +3282,7 @@ _NODISCARD bool is_partitioned(_ExPo&&, const _FwdIt _First, const _FwdIt _Last,
template <class _RanIt, class _Pr>
struct _Static_partitioned_is_heap_until {
using _Diff = _Iter_diff_t<_RanIt>;
_Static_partition_team<_Iter_diff_t<_RanIt>> _Team;
_Static_partition_team<_Diff> _Team;
_RanIt _Range_first;
_Pr _Pred;
_Parallel_find_results<_RanIt> _Results;
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/forward_list
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public:
return _Sort2(_BFirst, _Pred);
}

const auto _Half_bound = _Bound >> 1;
const auto _Half_bound = _Bound / 2;
const auto _BMid = _Sort(_BFirst, _Half_bound, _Pred);
if (!_BMid->_Next) {
return _BMid;
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/list
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,8 @@ public:
break;
}

auto _Mid = _Sort(_First, _Size >> 1, _Pred);
const auto _Last = _Sort(_Mid, _Size - (_Size >> 1), _Pred);
auto _Mid = _Sort(_First, _Size / 2, _Pred);
const auto _Last = _Sort(_Mid, _Size - _Size / 2, _Pred);
_First = _Merge_same(_First, _Mid, _Last, _Pred);
return _Last;
}
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/memory_resource
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ namespace pmr {
return _Max_allocation;
}

return (_Size + ((_Size + 1) >> 1) + alignof(_Header) - 1) & _Max_allocation;
return (_Size + (_Size + 1) / 2 + alignof(_Header) - 1) & _Max_allocation;
}

void _Increase_capacity(const size_t _Bytes, const size_t _Align) { // obtain a new buffer from upstream
Expand Down
8 changes: 4 additions & 4 deletions stl/inc/numeric
Original file line number Diff line number Diff line change
Expand Up @@ -967,19 +967,19 @@ _NODISCARD constexpr _Ty midpoint(const _Ty _Val1, const _Ty _Val2) noexcept {
const auto _Val1_u = static_cast<_Unsigned>(_Val1);
const auto _Val2_u = static_cast<_Unsigned>(_Val2);
if (_Val1 > _Val2) {
return static_cast<_Ty>(_Val1 - static_cast<_Ty>(static_cast<_Unsigned>(_Val1_u - _Val2_u) >> 1));
return static_cast<_Ty>(_Val1 - static_cast<_Ty>(static_cast<_Unsigned>(_Val1_u - _Val2_u) / 2));
} else {
return static_cast<_Ty>(_Val1 + static_cast<_Ty>(static_cast<_Unsigned>(_Val2_u - _Val1_u) >> 1));
return static_cast<_Ty>(_Val1 + static_cast<_Ty>(static_cast<_Unsigned>(_Val2_u - _Val1_u) / 2));
}
}
}

template <class _Ty, enable_if_t<is_object_v<_Ty>, int> = 0>
_NODISCARD constexpr _Ty* midpoint(_Ty* const _Val1, _Ty* const _Val2) noexcept /* strengthened */ {
if (_Val1 > _Val2) {
return _Val1 - ((_Val1 - _Val2) >> 1);
return _Val1 - ((_Val1 - _Val2) >> 1); // shift for codegen
} else {
return _Val1 + ((_Val2 - _Val1) >> 1);
return _Val1 + ((_Val2 - _Val1) >> 1); // shift for codegen
}
}
#endif // _HAS_CXX20
Expand Down
12 changes: 4 additions & 8 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ struct pair { // store a pair of values
#if _HAS_CONDITIONAL_EXPLICIT
template <class _Uty1 = _Ty1, class _Uty2 = _Ty2,
enable_if_t<conjunction_v<is_copy_constructible<_Uty1>, is_copy_constructible<_Uty2>>, int> = 0>
constexpr explicit(!is_convertible<const _Uty1&, _Uty1>::value // TRANSITION, VSO-946746
|| !is_convertible<const _Uty2&, _Uty2>::value) // TRANSITION, VSO-946746
constexpr explicit(!is_convertible_v<const _Uty1&, _Uty1> || !is_convertible_v<const _Uty2&, _Uty2>)
pair(const _Ty1& _Val1, const _Ty2& _Val2) noexcept(
is_nothrow_copy_constructible_v<_Uty1>&& is_nothrow_copy_constructible_v<_Uty2>) // strengthened
: first(_Val1), second(_Val2) {}
Expand All @@ -142,8 +141,7 @@ struct pair { // store a pair of values
#if _HAS_CONDITIONAL_EXPLICIT
template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
constexpr explicit(!is_convertible<_Other1, _Ty1>::value // TRANSITION, VSO-946746
|| !is_convertible<_Other2, _Ty2>::value) // TRANSITION, VSO-946746
constexpr explicit(!is_convertible_v<_Other1, _Ty1> || !is_convertible_v<_Other2, _Ty2>)
pair(_Other1&& _Val1, _Other2&& _Val2) noexcept(
is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened
: first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {}
Expand Down Expand Up @@ -172,8 +170,7 @@ struct pair { // store a pair of values
template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, const _Other1&>, is_constructible<_Ty2, const _Other2&>>,
int> = 0>
constexpr explicit(!is_convertible<const _Other1&, _Ty1>::value // TRANSITION, VSO-946746
|| !is_convertible<const _Other2&, _Ty2>::value) // TRANSITION, VSO-946746
constexpr explicit(!is_convertible_v<const _Other1&, _Ty1> || !is_convertible_v<const _Other2&, _Ty2>)
pair(const pair<_Other1, _Other2>& _Right) noexcept(is_nothrow_constructible_v<_Ty1, const _Other1&>&&
is_nothrow_constructible_v<_Ty2, const _Other2&>) // strengthened
: first(_Right.first), second(_Right.second) {}
Expand All @@ -200,8 +197,7 @@ struct pair { // store a pair of values
#if _HAS_CONDITIONAL_EXPLICIT
template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
constexpr explicit(!is_convertible<_Other1, _Ty1>::value // TRANSITION, VSO-946746
|| !is_convertible<_Other2, _Ty2>::value) // TRANSITION, VSO-946746
constexpr explicit(!is_convertible_v<_Other1, _Ty1> || !is_convertible_v<_Other2, _Ty2>)
pair(pair<_Other1, _Other2>&& _Right) noexcept(
is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened
: first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {}
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/xhash
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ public:
// In testing, hash<size_t>{}(size_t{}) takes about 14 times as much time as assigning a pointer, or
// ~7-8 times as much as clearing a bucket. Therefore, if we would need to assign over more than 8 times
// as many buckets as elements, remove element-by-element.
if ((bucket_count() >> 3) > _Oldsize) {
if (bucket_count() / 8 > _Oldsize) {
const auto _Head = _List._Mypair._Myval2._Myhead;
_Unchecked_erase(_Head->_Next, _Head);
return;
Expand Down

0 comments on commit 53cdb9f

Please sign in to comment.