diff --git a/test/boost/chunked_vector_test.cc b/test/boost/chunked_vector_test.cc index bad03b107d..f2e5ba411c 100644 --- a/test/boost/chunked_vector_test.cc +++ b/test/boost/chunked_vector_test.cc @@ -178,6 +178,19 @@ BOOST_AUTO_TEST_CASE(tests_constructor_exception_safety) { } } +BOOST_AUTO_TEST_CASE(tests_constructor_exception_safety_range) { + auto checker = exception_safety_checker(); + auto v = std::vector(100, exception_safe_class(checker)); + checker.set_countdown(5); + try { + auto u = utils::chunked_vector(std::from_range, v); + BOOST_REQUIRE(false); + } catch (...) { + v.clear(); + BOOST_REQUIRE(checker.ok()); + } +} + BOOST_AUTO_TEST_CASE(tests_reserve_partial) { auto rand = std::default_random_engine(); auto size_dist = std::uniform_int_distribution(1, 1 << 12); @@ -429,6 +442,13 @@ BOOST_AUTO_TEST_CASE(test_initializer_list_ctor) { BOOST_REQUIRE(vit == vec.end()); } + +BOOST_AUTO_TEST_CASE(test_range_ctor) { + auto range = std::views::iota(0, 12345); + auto vec = range | std::ranges::to>(); + BOOST_REQUIRE(std::ranges::equal(range, vec)); +} + BOOST_AUTO_TEST_CASE(test_value_default_init_ctor) { int n = 17; auto vec = utils::chunked_vector(n); diff --git a/utils/chunked_vector.hh b/utils/chunked_vector.hh index 669b7b51b5..aa6b31076c 100644 --- a/utils/chunked_vector.hh +++ b/utils/chunked_vector.hh @@ -104,6 +104,11 @@ public: chunked_vector(chunked_vector&& x) noexcept; template chunked_vector(Iterator begin, Iterator end); + + template + requires std::convertible_to, T> + chunked_vector(std::from_range_t, Range&& range); + chunked_vector(std::initializer_list x); explicit chunked_vector(size_t n, const T& value = T()); ~chunked_vector(); @@ -372,6 +377,28 @@ chunked_vector::chunked_vector(Iterator begin, Ite } } +template +template +requires std::convertible_to, T> +chunked_vector::chunked_vector(std::from_range_t, Range&& range) + : chunked_vector() { + if constexpr (std::ranges::forward_range) { + size_t size = std::ranges::distance(range); + reserve(size); + auto begin = std::ranges::begin(range); + for (size_t i = 0; _size < size; ++i) { + T* dst = _chunks[i].get(); + auto now = std::min(size - _size, max_chunk_capacity()); + begin = std::ranges::uninitialized_copy_n(begin, now, dst, dst + now).in; + // Update _size incrementally to let the destructor + // know how much data to destroy on exception + _size += now; + } + } else { + std::ranges::copy(range, std::back_inserter(*this)); + } +} + template chunked_vector::chunked_vector(std::initializer_list x) : chunked_vector(std::begin(x), std::end(x)) {