From 0c6572cfa8a4db48c713ac7151b3ae40bd9dfa9c Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 5 Oct 2023 15:04:12 +0800 Subject: [PATCH 1/3] Use unchecked iterators in `deque` Driven-by changes - introduce `_At` member functions to make some other members clearer - fix `shrink_to_fit` --- stl/inc/deque | 61 +++++++++++-------- .../test.cpp | 28 +++++++++ 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 2f23acdad8..f47b69e0b1 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -995,7 +995,8 @@ public: if ((empty() && _Mapsize() > 0) || (!empty() && size() <= _Newcapacity && _Newcapacity < _Oldcapacity)) { // worth shrinking, do it - deque _Tmp(_STD make_move_iterator(begin()), _STD make_move_iterator(end())); + deque _Tmp( + _STD make_move_iterator(_Unchecked_begin()), _STD make_move_iterator(_Unchecked_end()), _Getal()); swap(_Tmp); } } @@ -1005,7 +1006,7 @@ public: _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Get_data()._Subscript(_Myoff() + _Pos); + return _At(_Pos); } _NODISCARD reference operator[](size_type _Pos) noexcept /* strengthened */ { @@ -1013,7 +1014,7 @@ public: _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Get_data()._Subscript(_Myoff() + _Pos); + return _At(_Pos); } _NODISCARD const_reference at(size_type _Pos) const { @@ -1021,7 +1022,7 @@ public: _Xran(); } - return _Get_data()._Subscript(_Myoff() + _Pos); + return _At(_Pos); } _NODISCARD reference at(size_type _Pos) { @@ -1029,7 +1030,7 @@ public: _Xran(); } - return _Get_data()._Subscript(_Myoff() + _Pos); + return _At(_Pos); } _NODISCARD reference front() noexcept /* strengthened */ { @@ -1037,7 +1038,7 @@ public: _STL_VERIFY(!empty(), "front() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *_Unchecked_begin(); + return _At(0); } _NODISCARD const_reference front() const noexcept /* strengthened */ { @@ -1045,7 +1046,7 @@ public: _STL_VERIFY(!empty(), "front() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *_Unchecked_begin(); + return _At(0); } _NODISCARD reference back() noexcept /* strengthened */ { @@ -1053,7 +1054,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *_Prev_iter(_Unchecked_end()); + return _At(_Mysize() - 1); } _NODISCARD const_reference back() const noexcept /* strengthened */ { @@ -1061,7 +1062,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *_Prev_iter(_Unchecked_end()); + return _At(_Mysize() - 1); } private: @@ -1201,7 +1202,7 @@ public: } const auto _Num = static_cast(_Mysize() - _Oldsize); - _STD reverse(begin(), begin() + _Num); + _STD reverse(_Unchecked_begin(), _Unchecked_begin() + _Num); } _Guard._Container = nullptr; } @@ -1346,7 +1347,7 @@ private: } void _Insert_n(const_iterator _Where, size_type _Count, const _Ty& _Val) { // insert _Count * _Val at _Where - iterator _Mid; + _Unchecked_iterator _Mid; size_type _Num; size_type _Off = static_cast(_Where - begin()); size_type _Oldsize = _Mysize(); @@ -1363,22 +1364,22 @@ private: push_front(_Val); // push excess values } for (_Num = _Off; _Num > 0; --_Num) { - push_front(begin()[static_cast(_Count - 1)]); // push prefix + push_front(_At(_Count - 1)); } - _Mid = begin() + static_cast(_Count); + _Mid = _Unchecked_begin() + static_cast(_Count); _STD fill_n(_Mid, _Off, _Val); // fill in rest of values } else { // insert not longer than prefix for (_Num = _Count; _Num > 0; --_Num) { - push_front(begin()[static_cast(_Count - 1)]); // push part of prefix + push_front(_At(_Count - 1)); // push part of prefix } - _Mid = begin() + static_cast(_Count); + _Mid = _Unchecked_begin() + static_cast(_Count); _Alloc_temporary2<_Alty> _Tmp(_Getal(), _Val); // in case _Val is in sequence _STD move(_Mid + static_cast(_Count), _Mid + static_cast(_Off), _Mid); // copy rest of prefix - _STD fill(begin() + static_cast(_Off), _Mid + static_cast(_Off), - _Tmp._Get_value()); // fill in values + _STD fill(_Unchecked_begin() + static_cast(_Off), + _Mid + static_cast(_Off), _Tmp._Get_value()); // fill in values } _Guard._Container = nullptr; } else { // closer to back @@ -1389,18 +1390,17 @@ private: _Emplace_back_internal(_Val); // push excess values } for (_Num = 0; _Num < _Rem; ++_Num) { - _Emplace_back_internal(begin()[static_cast(_Off + _Num)]); // push suffix + _Emplace_back_internal(_At(_Off + _Num)); // push suffix } - _Mid = begin() + static_cast(_Off); + _Mid = _Unchecked_begin() + static_cast(_Off); _STD fill_n(_Mid, _Rem, _Val); // fill in rest of values } else { // insert not longer than prefix for (_Num = 0; _Num < _Count; ++_Num) { - _Emplace_back_internal( - begin()[static_cast(_Off + _Rem - _Count + _Num)]); // push part of prefix + _Emplace_back_internal(_At(_Off + _Rem - _Count + _Num)); // push part of prefix } - _Mid = begin() + static_cast(_Off); + _Mid = _Unchecked_begin() + static_cast(_Off); _Alloc_temporary2<_Alty> _Tmp(_Getal(), _Val); // in case _Val is in sequence _STD move_backward(_Mid, _Mid + static_cast(_Rem - _Count), _Mid + static_cast(_Rem)); // copy rest of prefix @@ -1483,13 +1483,16 @@ public: return _First; } - if (_Off < static_cast(end() - _Last)) { // closer to front - _STD move_backward(begin(), _First, _Last); // copy over hole + auto _Unchecked_first = _First._Unwrapped(); + auto _Unchecked_last = _Last._Unwrapped(); + + if (_Off < static_cast(_Unchecked_end() - _Unchecked_last)) { // closer to front + _STD move_backward(_Unchecked_begin(), _Unchecked_first, _Unchecked_last); // copy over hole for (; _Count > 0; --_Count) { pop_front(); // pop copied elements } } else { // closer to back - _STD move(_Last, end(), _First); // copy over hole + _STD move(_Unchecked_last, _Unchecked_end(), _Unchecked_first); // copy over hole for (; _Count > 0; --_Count) { pop_back(); // pop copied elements } @@ -1692,6 +1695,14 @@ private: return static_cast<_Map_difference_type>(_Get_data()._Mapsize); } + reference _At(size_type _Pos) noexcept { + return _Get_data()._Subscript(_Myoff() + _Pos); + } + + const_reference _At(size_type _Pos) const noexcept { + return _Get_data()._Subscript(_Myoff() + _Pos); + } + _Compressed_pair<_Alty, _Scary_val> _Mypair; }; diff --git a/tests/std/tests/VSO_0000000_allocator_propagation/test.cpp b/tests/std/tests/VSO_0000000_allocator_propagation/test.cpp index 9585dca3ea..5d94107083 100644 --- a/tests/std/tests/VSO_0000000_allocator_propagation/test.cpp +++ b/tests/std/tests/VSO_0000000_allocator_propagation/test.cpp @@ -488,6 +488,33 @@ _CONSTEXPR20 bool test_sequence() { } +template +void test_deque_shrink_to_fit_per_alloc() { + { + deque d(1729, 0, Alloc{42}); + d.resize(0); + d.shrink_to_fit(); + assert(d.get_allocator().id() == 42); + } + { + deque d(1729, 0, Alloc{42}); + d.resize(128); + d.shrink_to_fit(); + assert(d.get_allocator().id() == 42); + } +} + +void test_deque_shrink_to_fit() { // MSVC STL's deque::shrink_to_fit relies on swap + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); + test_deque_shrink_to_fit_per_alloc>(); +} + + void test_flist_copy_ctor() { forward_list> src({10, 20, 30}, StationaryAlloc(11)); auto src_it = src.begin(); @@ -1849,6 +1876,7 @@ int main() { static_assert(test_string()); #endif // _HAS_CXX20 + test_deque_shrink_to_fit(); test_flist(); test_string(); test_vb(); From 8a813d5cdac8505c0e9da5ebe47ecefbe2f14440 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 5 Oct 2023 16:20:17 -0700 Subject: [PATCH 2/3] `_At` => `_Subscript` --- stl/inc/deque | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index f47b69e0b1..ff26d8377b 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1006,7 +1006,7 @@ public: _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(_Pos); + return _Subscript(_Pos); } _NODISCARD reference operator[](size_type _Pos) noexcept /* strengthened */ { @@ -1014,7 +1014,7 @@ public: _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(_Pos); + return _Subscript(_Pos); } _NODISCARD const_reference at(size_type _Pos) const { @@ -1022,7 +1022,7 @@ public: _Xran(); } - return _At(_Pos); + return _Subscript(_Pos); } _NODISCARD reference at(size_type _Pos) { @@ -1030,7 +1030,7 @@ public: _Xran(); } - return _At(_Pos); + return _Subscript(_Pos); } _NODISCARD reference front() noexcept /* strengthened */ { @@ -1038,7 +1038,7 @@ public: _STL_VERIFY(!empty(), "front() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(0); + return _Subscript(0); } _NODISCARD const_reference front() const noexcept /* strengthened */ { @@ -1046,7 +1046,7 @@ public: _STL_VERIFY(!empty(), "front() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(0); + return _Subscript(0); } _NODISCARD reference back() noexcept /* strengthened */ { @@ -1054,7 +1054,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(_Mysize() - 1); + return _Subscript(_Mysize() - 1); } _NODISCARD const_reference back() const noexcept /* strengthened */ { @@ -1062,7 +1062,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _At(_Mysize() - 1); + return _Subscript(_Mysize() - 1); } private: @@ -1364,14 +1364,14 @@ private: push_front(_Val); // push excess values } for (_Num = _Off; _Num > 0; --_Num) { - push_front(_At(_Count - 1)); + push_front(_Subscript(_Count - 1)); } _Mid = _Unchecked_begin() + static_cast(_Count); _STD fill_n(_Mid, _Off, _Val); // fill in rest of values } else { // insert not longer than prefix for (_Num = _Count; _Num > 0; --_Num) { - push_front(_At(_Count - 1)); // push part of prefix + push_front(_Subscript(_Count - 1)); // push part of prefix } _Mid = _Unchecked_begin() + static_cast(_Count); @@ -1390,14 +1390,14 @@ private: _Emplace_back_internal(_Val); // push excess values } for (_Num = 0; _Num < _Rem; ++_Num) { - _Emplace_back_internal(_At(_Off + _Num)); // push suffix + _Emplace_back_internal(_Subscript(_Off + _Num)); // push suffix } _Mid = _Unchecked_begin() + static_cast(_Off); _STD fill_n(_Mid, _Rem, _Val); // fill in rest of values } else { // insert not longer than prefix for (_Num = 0; _Num < _Count; ++_Num) { - _Emplace_back_internal(_At(_Off + _Rem - _Count + _Num)); // push part of prefix + _Emplace_back_internal(_Subscript(_Off + _Rem - _Count + _Num)); // push part of prefix } _Mid = _Unchecked_begin() + static_cast(_Off); @@ -1695,11 +1695,11 @@ private: return static_cast<_Map_difference_type>(_Get_data()._Mapsize); } - reference _At(size_type _Pos) noexcept { + reference _Subscript(size_type _Pos) noexcept { return _Get_data()._Subscript(_Myoff() + _Pos); } - const_reference _At(size_type _Pos) const noexcept { + const_reference _Subscript(size_type _Pos) const noexcept { return _Get_data()._Subscript(_Myoff() + _Pos); } From 744709bed45fa459cb687b181ba3f6c14c82a74f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 5 Oct 2023 16:21:11 -0700 Subject: [PATCH 3/3] Restore `// push prefix` comment. --- stl/inc/deque | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/deque b/stl/inc/deque index ff26d8377b..56b0a70856 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1364,7 +1364,7 @@ private: push_front(_Val); // push excess values } for (_Num = _Off; _Num > 0; --_Num) { - push_front(_Subscript(_Count - 1)); + push_front(_Subscript(_Count - 1)); // push prefix } _Mid = _Unchecked_begin() + static_cast(_Count);