Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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
62 changes: 33 additions & 29 deletions stl/inc/deque
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,31 @@ public:
return begin() + static_cast<difference_type>(_Off);
}

private:
enum class _Pop_direction : bool {
_Front,
_Back,
};

template <_Pop_direction _Direction>
struct _NODISCARD _Restore_old_size_guard {
deque* _Container;
const size_type _Oldsize;

~_Restore_old_size_guard() {
if (_Container) {
while (_Oldsize < _Container->_Mysize()) {
if constexpr (_Direction == _Pop_direction::_Front) {
_Container->pop_front(); // restore old size, at least
} else {
_Container->pop_back(); // restore old size, at least
}
}
}
}
};

public:
template <class _Iter, enable_if_t<_Is_iterator_v<_Iter>, int> = 0>
iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) {
// insert [_First, _Last) at _Where, input iterators
Expand All @@ -1237,37 +1262,25 @@ public:

if (_UFirst != _ULast) {
if (_Off <= _Mysize() / 2) { // closer to front, push to front then rotate
_TRY_BEGIN
_Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize};
for (; _UFirst != _ULast; ++_UFirst) {
emplace_front(*_UFirst); // prepend flipped
}

_CATCH_ALL
while (_Oldsize < _Mysize()) {
pop_front(); // restore old size, at least
}

_RERAISE;
_CATCH_END
_Guard._Container = nullptr;

size_type _Num = _Mysize() - _Oldsize;
_STD reverse(begin(), begin() + static_cast<difference_type>(_Num)); // flip new stuff in place
_STD rotate(begin(), begin() + static_cast<difference_type>(_Num),
begin() + static_cast<difference_type>(_Num + _Off));
} else { // closer to back
_TRY_BEGIN
_Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize};
_Orphan_all();
for (; _UFirst != _ULast; ++_UFirst) {
_Emplace_back_internal(*_UFirst);
}

_CATCH_ALL
while (_Oldsize < _Mysize()) {
pop_back(); // restore old size, at least
}

_RERAISE;
_CATCH_END
_Guard._Container = nullptr;

_STD rotate(begin() + static_cast<difference_type>(_Off),
begin() + static_cast<difference_type>(_Oldsize), end());
Expand Down Expand Up @@ -1362,7 +1375,7 @@ private:
#endif // _ITERATOR_DEBUG_LEVEL == 2

if (_Off < _Rem) { // closer to front
_TRY_BEGIN
_Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize};
if (_Off < _Count) { // insert longer than prefix
for (_Num = _Count - _Off; 0 < _Num; --_Num) {
push_front(_Val); // push excess values
Expand All @@ -1385,15 +1398,9 @@ private:
_STD fill(begin() + static_cast<difference_type>(_Off), _Mid + static_cast<difference_type>(_Off),
_Tmp._Get_value()); // fill in values
}
_CATCH_ALL
while (_Oldsize < _Mysize()) {
pop_front(); // restore old size, at least
}

_RERAISE;
_CATCH_END
_Guard._Container = nullptr;
} else { // closer to back
_TRY_BEGIN
_Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize};
if (_Rem < _Count) { // insert longer than suffix
_Orphan_all();
for (_Num = _Count - _Rem; 0 < _Num; --_Num) {
Expand All @@ -1418,10 +1425,7 @@ private:
_STD fill(_Mid, _Mid + static_cast<difference_type>(_Count),
_Tmp._Get_value()); // fill in values
}
_CATCH_ALL
_Erase_last_n(_Mysize() - _Oldsize);
_RERAISE;
_CATCH_END
_Guard._Container = nullptr;
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ tests\GH_002030_asan_annotate_vector
tests\GH_002039_byte_is_not_trivially_swappable
tests\GH_002058_debug_iterator_race
tests\GH_002120_streambuf_seekpos_and_seekoff
tests\GH_002307_usual_scope_guard
tests\GH_002488_promise_not_default_constructible_types
tests\LWG2597_complex_branch_cut
tests\LWG3018_shared_ptr_function
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_002307_usual_scope_guard/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
102 changes: 102 additions & 0 deletions tests/std/tests/GH_002307_usual_scope_guard/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <cassert>
#include <cstring>
#include <deque>
#include <stdexcept>

using namespace std;

struct countdown {
int val;

static int count;

void tick() {
if (count == 0) {
throw runtime_error{"GO"};
} else {
--count;
}
}

countdown(const int init) : val(init) {
tick();
}

countdown(const countdown& other) : val(other.val) {
tick();
}

countdown& operator=(const countdown& other) {
tick();
val = other.val;
return *this;
}

bool operator==(int other) const {
return val == other;
}
};

int countdown::count = 0;

constexpr int init_data[] = {1, 2, 3, 4, 5, 6, 7};
constexpr int more_data[] = {10, 11, 12, 13, 14};

template <class Container>
void check(const Container& c) {
assert(equal(c.begin(), c.end(), begin(init_data), end(init_data)));
}

void check_exception(const runtime_error& ex) {
assert(strcmp(ex.what(), "GO") == 0);
}

void test_deque() {
countdown::count = 8;

deque<countdown> dq(begin(init_data), end(init_data));

try {
countdown::count = 3;
dq.insert(dq.end() - 2, begin(more_data), end(more_data));
assert(false); // Should have thrown an exception
} catch (const runtime_error& ex) {
check_exception(ex);
check(dq);
}

try {
countdown::count = 3;
dq.insert(dq.begin() + 2, begin(more_data), end(more_data));
assert(false); // Should have thrown an exception
} catch (const runtime_error& ex) {
check_exception(ex);
check(dq);
}

try {
countdown::count = 3;
dq.insert(dq.end() - 2, 6, 10);
assert(false); // Should have thrown an exception
} catch (const runtime_error& ex) {
check_exception(ex);
check(dq);
}

try {
countdown::count = 3;
dq.insert(dq.begin() + 2, 6, 11);
assert(false); // Should have thrown an exception
} catch (const runtime_error& ex) {
check_exception(ex);
check(dq);
}
}

int main() {
test_deque();
}