Files
container/experimental/segmented_fill_n_test.cpp
T

182 lines
6.0 KiB
C++

//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/experimental/segmented_fill_n.hpp>
#include "../test/lightweight_test.hpp"
#include "segmented_test_helper.hpp"
#include <boost/container/vector.hpp>
using namespace boost::container;
//A count that spans several segments, with the returned iterator checked
//against the first element left untouched.
void test_fill_n_partial()
{
test_detail::seg_vector<int> sv;
int a1[] = {1, 2, 3};
int a2[] = {4, 5, 6, 7};
int a3[] = {8, 9};
sv.add_segment_range(a1, a1 + 3);
sv.add_segment_range(a2, a2 + 4);
sv.add_segment_range(a3, a3 + 2);
test_detail::seg_vector<int>::iterator result = segmented_fill_n(sv.begin(), 5, 0);
test_detail::seg_vector<int>::iterator it = sv.begin();
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST(it == result);
BOOST_TEST_EQ(*it, 6); ++it;
BOOST_TEST_EQ(*it, 7); ++it;
BOOST_TEST_EQ(*it, 8); ++it;
BOOST_TEST_EQ(*it, 9);
}
//A count that stops short of the end of the only segment.
void test_fill_n_single_segment()
{
test_detail::seg_vector<int> sv;
sv.add_segment(5, 0);
segmented_fill_n(sv.begin(), 3, 77);
test_detail::seg_vector<int>::iterator it = sv.begin();
BOOST_TEST_EQ(*it, 77); ++it;
BOOST_TEST_EQ(*it, 77); ++it;
BOOST_TEST_EQ(*it, 77); ++it;
BOOST_TEST_EQ(*it, 0); ++it;
BOOST_TEST_EQ(*it, 0);
}
void test_fill_n_non_segmented()
{
boost::container::vector<int> v(5, 0);
boost::container::vector<int>::iterator result = segmented_fill_n(v.begin(), 3, 7);
BOOST_TEST(result == v.begin() + 3);
BOOST_TEST_EQ(v[0], 7);
BOOST_TEST_EQ(v[1], 7);
BOOST_TEST_EQ(v[2], 7);
BOOST_TEST_EQ(v[3], 0);
BOOST_TEST_EQ(v[4], 0);
}
// Fills count elements from a chosen offset into a range whose segmentation
// shape is dictated by a branch spec, so that every level of the recursive
// dispatch is exercised on its single-segment path, on its multi-segment path
// and on the multi-segment path with empty segments interleaved. Sweeping
// both the offset and the count covers a count that stops short of the end of
// a segment, one that exactly consumes it and one that spans several; a count
// larger than the range is deliberately never tried, because the public API
// takes no end bound and so has nothing to stop against.
//
// The returned iterator is compared against iter_at, which normalises by
// stepping: at an exact segment boundary that lands on the next non-empty
// segment's begin, so a return value left dangling at the old segment's end
// compares unequal.
struct fill_n_shape_check
{
std::size_t offset;
std::size_t count;
fill_n_shape_check(std::size_t o, std::size_t k) : offset(o), count(k) {}
template<class Cont>
void operator()(Cont& c, std::size_t n, const char* spec) const
{
typedef typename Cont::iterator iter_t;
const boost::container::vector<int> before = test_detail::flatten_n_ints(c, n);
const iter_t r = segmented_fill_n(test_detail::iter_at(c, offset), count, 42);
BOOST_TEST(r == test_detail::iter_at(c, offset + count));
const boost::container::vector<int> after = test_detail::flatten_n_ints(c, n);
BOOST_TEST_EQ(after.size(), before.size());
for(std::size_t i = 0; i != after.size(); ++i)
BOOST_TEST_EQ(after[i], (i >= offset && i < offset + count) ? 42 : before[i]);
BOOST_TEST(test_detail::filler_intact(c, n, -999));
BOOST_TEST(spec != 0);
}
};
void test_fill_n_shape_matrix()
{
int vals[16];
for(int i = 0; i != 16; ++i)
vals[i] = i + 1;
const std::size_t sizes[] = { 0u, 1u, 2u, 5u, 12u };
for(std::size_t s = 0; s != sizeof(sizes)/sizeof(sizes[0]); ++s) {
const std::size_t n = sizes[s];
for(std::size_t offset = 0; offset <= n; ++offset)
for(std::size_t k = 0; offset + k <= n; ++k)
test_detail::for_each_shape_all<int>(vals, n, -999, fill_n_shape_check(offset, k));
}
}
//////////////////////////////////////////////////////////////////////////////
// Assignment count.
//
// [alg.fill] mandates "Exactly n assignments", so a slot written twice at a
// segment boundary is a conformance failure. The count is taken from the
// value type, fill_n having no functor to instrument.
//////////////////////////////////////////////////////////////////////////////
struct fill_n_assignment_check
{
std::size_t offset;
std::size_t count;
fill_n_assignment_check(std::size_t o, std::size_t k) : offset(o), count(k) {}
template<class Cont>
void operator()(Cont& c, std::size_t n, const char* spec) const
{
const test_detail::counted_int value(42);
test_detail::counted_int_ops().reset();
segmented_fill_n(test_detail::iter_at(c, offset), count, value);
const std::size_t applied = test_detail::counted_int_ops().assign;
BOOST_TEST_EQ(applied, count);
BOOST_TEST(spec != 0 && n >= count);
}
};
void test_fill_n_assignment_count()
{
int vals[16];
for(int i = 0; i != 16; ++i)
vals[i] = i + 1;
const std::size_t sizes[] = { 0u, 1u, 2u, 5u, 12u };
for(std::size_t s = 0; s != sizeof(sizes)/sizeof(sizes[0]); ++s) {
const std::size_t n = sizes[s];
for(std::size_t offset = 0; offset <= n; ++offset)
for(std::size_t k = 0; offset + k <= n; ++k)
test_detail::for_each_shape_all<test_detail::counted_int>
(vals, n, -999, fill_n_assignment_check(offset, k));
}
}
int main()
{
test_fill_n_shape_matrix();
test_fill_n_partial();
test_fill_n_single_segment();
test_fill_n_non_segmented();
test_fill_n_assignment_count();
return boost::report_errors();
}