utils: chunked_vector: implement insert() for single-element inserts

partition_range_compat's unwrap() needs insert if we are to
use it for chunked_vector (which we do).

Implement using push_back() and std::rotate().

emplace(iterator, args) is also implemented, though the benefit
is diluted (it will be moved after construction).

The implementation isn't optimal - if T is trivially copyable
then using std::memmove() will be much faster that std::rotate(),
but this complex optimization is left for later.

Unit tests are added.

(cherry picked from commit 5301f3d0b5)
This commit is contained in:
Avi Kivity
2025-05-13 22:57:29 +03:00
committed by Asias He
parent 23bcff5c52
commit efad391fac
2 changed files with 75 additions and 1 deletions

View File

@@ -32,7 +32,7 @@ using deque = std::deque<int>;
BOOST_AUTO_TEST_CASE(test_random_walk) {
auto rand = std::default_random_engine();
auto op_gen = std::uniform_int_distribution<unsigned>(0, 9);
auto op_gen = std::uniform_int_distribution<unsigned>(0, 10);
auto nr_dist = std::geometric_distribution<size_t>(0.7);
deque d;
disk_array c;
@@ -105,6 +105,13 @@ BOOST_AUTO_TEST_CASE(test_random_walk) {
d.resize(nr);
break;
}
case 10: {
auto pos = std::uniform_int_distribution<size_t>(0, d.size())(rand);
auto n = rand();
c.insert(c.begin() + pos, n);
d.insert(d.begin() + pos, n);
break;
}
default:
abort();
}
@@ -467,3 +474,37 @@ BOOST_AUTO_TEST_CASE(test_value_init_ctor) {
BOOST_REQUIRE_EQUAL(*it, v);
}
}
BOOST_AUTO_TEST_CASE(test_insert_single) {
auto vec = utils::chunked_vector<int, 8>();
auto r1 = vec.insert(vec.begin(), 1);
BOOST_REQUIRE_EQUAL(vec.size(), 1);
BOOST_REQUIRE_EQUAL(r1 - std::begin(vec), 0);
BOOST_REQUIRE_EQUAL(vec[0], 1);
auto r2 = vec.insert(vec.begin(), 2);
BOOST_REQUIRE_EQUAL(vec.size(), 2);
BOOST_REQUIRE_EQUAL(r2 - std::begin(vec), 0);
BOOST_REQUIRE_EQUAL(vec[0], 2);
BOOST_REQUIRE_EQUAL(vec[1], 1);
auto r3 = vec.insert(vec.end(), 3);
BOOST_REQUIRE_EQUAL(vec.size(), 3);
BOOST_REQUIRE_EQUAL(r3 - std::begin(vec), 2);
BOOST_REQUIRE_EQUAL(vec[0], 2);
BOOST_REQUIRE_EQUAL(vec[1], 1);
BOOST_REQUIRE_EQUAL(vec[2], 3);
auto r4 = vec.insert(vec.end() - 2, 4);
BOOST_REQUIRE_EQUAL(vec.size(), 4);
BOOST_REQUIRE_EQUAL(r4 - std::begin(vec), 1);
BOOST_REQUIRE_EQUAL(vec[0], 2);
BOOST_REQUIRE_EQUAL(vec[1], 4);
BOOST_REQUIRE_EQUAL(vec[2], 1);
BOOST_REQUIRE_EQUAL(vec[3], 3);
auto r5 = vec.emplace(vec.end() - 2, 6);
BOOST_REQUIRE_EQUAL(vec.size(), 5);
BOOST_REQUIRE_EQUAL(r5 - std::begin(vec), 2);
BOOST_REQUIRE_EQUAL(vec[0], 2);
BOOST_REQUIRE_EQUAL(vec[1], 4);
BOOST_REQUIRE_EQUAL(vec[2], 6);
BOOST_REQUIRE_EQUAL(vec[3], 1);
BOOST_REQUIRE_EQUAL(vec[4], 3);
}

View File

@@ -321,6 +321,11 @@ public:
bool operator==(const chunked_vector& x) const {
return std::ranges::equal(*this, x);
}
public:
iterator insert(const_iterator pos, const T& x);
iterator insert(const_iterator pos, T&& x);
template <typename... Args>
iterator emplace(const_iterator pos, Args&&... args);
};
template<typename T, size_t max_contiguous_allocation>
@@ -595,6 +600,34 @@ chunked_vector<T, max_contiguous_allocation>::clear() {
shrink_to_fit();
}
template <typename T, size_t max_contiguous_allocation>
typename chunked_vector<T, max_contiguous_allocation>::iterator
chunked_vector<T, max_contiguous_allocation>::insert(const_iterator pos, const T& x) {
auto insert_idx = pos - begin();
push_back(x);
std::rotate(begin() + insert_idx, end() - 1, end());
return begin() + insert_idx;
}
template <typename T, size_t max_contiguous_allocation>
typename chunked_vector<T, max_contiguous_allocation>::iterator
chunked_vector<T, max_contiguous_allocation>::insert(const_iterator pos, T&& x) {
auto insert_idx = pos - begin();
push_back(std::move(x));
std::rotate(begin() + insert_idx, end() - 1, end());
return begin() + insert_idx;
}
template <typename T, size_t max_contiguous_allocation>
template <typename... Args>
typename chunked_vector<T, max_contiguous_allocation>::iterator
chunked_vector<T, max_contiguous_allocation>::emplace(const_iterator pos, Args&&... args) {
auto insert_idx = pos - begin();
emplace_back(std::forward<Args>(args)...);
std::rotate(begin() + insert_idx, end() - 1, end());
return begin() + insert_idx;
}
template <typename T, size_t max_contiguous_allocation>
std::ostream& operator<<(std::ostream& os, const chunked_vector<T, max_contiguous_allocation>& v) {
fmt::print(os, "{}", v);