////////////////////////////////////////////////////////////////////////////// // // (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 #include #include "segmented_test_helper.hpp" #include using namespace boost::container; struct is_negative { bool operator()(int x) const { return x < 0; } }; struct equals_val { int v; equals_val(int x) : v(x) {} bool operator()(int x) const { return x == v; } }; // Satisfied by several elements at once, so that the early exit has to happen // at the first of them. The x > 0 term keeps the negative out-of-range guard // out, whatever the modulus. struct multiple_of { int m; multiple_of(int x) : m(x) {} bool operator()(int x) const { return x > 0 && (x % m) == 0; } }; void test_none_of_empty() { test_detail::seg_vector sv; BOOST_TEST(segmented_none_of(sv.begin(), sv.end(), is_negative())); } void test_none_of_non_segmented() { boost::container::vector v; v.push_back(1); v.push_back(2); v.push_back(3); BOOST_TEST(segmented_none_of(v.begin(), v.end(), is_negative())); v.clear(); v.push_back(1); v.push_back(-2); v.push_back(3); BOOST_TEST(!segmented_none_of(v.begin(), v.end(), is_negative())); } void test_none_of_sentinel_segmented() { test_detail::seg_vector sv; int a1[] = {1, 2, 3}; int a2[] = {4, 5, 6}; sv.add_segment_range(a1, a1 + 3); sv.add_segment_range(a2, a2 + 3); BOOST_TEST(segmented_none_of(sv.begin(), test_detail::make_sentinel(sv.end()), is_negative())); } void test_none_of_sentinel_non_segmented() { boost::container::vector v; v.push_back(1); v.push_back(-2); v.push_back(3); BOOST_TEST(!segmented_none_of(v.begin(), test_detail::make_sentinel(v.end()), is_negative())); } // Runs segmented_none_of over 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, its multi-segment and its empty-segment path. // segmented_none_of_dispatch is also what segmented_any_of and segmented_all_of // run on, but the sense of the answer differs, so each has its own matrix. template struct none_of_shape_check { Pred pred; explicit none_of_shape_check(Pred p) : pred(p) {} template void operator()(Cont& c, std::size_t n, const char* spec) const { typedef typename Cont::iterator iter_t; const iter_t first = c.begin(); const iter_t last = test_detail::iter_at(c, n); // Reference: naive scan over a flattened copy of the logical range. The // guard past the end is deliberately not part of it. const boost::container::vector flat = test_detail::flatten_n_ints(c, n); bool expected = true; for(std::size_t i = 0; i != flat.size(); ++i) { if(pred(flat[i])) { expected = false; break; } } BOOST_TEST_EQ(segmented_none_of(first, last, pred), expected); BOOST_TEST(spec != 0); } }; // Bidirectional and forward iterators instantiate every dispatch template // separately, so each shape is driven through both. template void run_none_of_shapes(const int* vals, std::size_t n, Pred pred) { test_detail::for_each_shape_all(vals, n, -999, none_of_shape_check(pred)); test_detail::for_each_shape_all_fwd(vals, n, -999, none_of_shape_check(pred)); } void test_none_of_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]; // The single hit at the first position, at every interior one and at the // last one; then a value no element has; then the guard value, which // lies past the end and must never turn a true answer into a false one. for(std::size_t v = 0; v <= n + 1u; ++v) run_none_of_shapes(vals, n, equals_val((v <= n) ? int(v) : -999)); // Predicates hit by many elements: all of them, every second one and // every third one, so a hit in an earlier segment coexists with hits in // later ones and the walk must stop at the first. run_none_of_shapes(vals, n, multiple_of(1)); run_none_of_shapes(vals, n, multiple_of(2)); run_none_of_shapes(vals, n, multiple_of(3)); // Hit by nothing at all, guard included. run_none_of_shapes(vals, n, is_negative()); } } //---------------------------------------------------------------------------- // Single-segment cases with data before the start of the range. The shape // matrix always starts its range at the container's first element, so the // lower bound is only exercised here: each range below leaves an element that // would be a hit just before its start, and a negative guard just past its // end. //---------------------------------------------------------------------------- void test_none_of_single_segment_interior() { test_detail::seg_vector sv; int a[] = {10, 20, 30, 40, 50, -60}; sv.add_segment_range(a, a + 6); typedef test_detail::seg_vector::iterator iter_t; const iter_t first = test_detail::iter_at(sv, 1); const iter_t last = test_detail::iter_at(sv, 5); BOOST_TEST(!segmented_none_of(first, last, equals_val(20))); BOOST_TEST(!segmented_none_of(first, last, equals_val(50))); BOOST_TEST(segmented_none_of(first, last, equals_val(35))); BOOST_TEST(segmented_none_of(first, last, equals_val(10))); BOOST_TEST(segmented_none_of(first, last, is_negative())); } void test_none_of_single_segment_sentinel() { test_detail::seg_vector sv; int a[] = {10, 20, 30, 40, 50, -60}; sv.add_segment_range(a, a + 6); typedef test_detail::seg_vector::iterator iter_t; const iter_t first = test_detail::iter_at(sv, 1); const iter_t last = test_detail::iter_at(sv, 5); BOOST_TEST(!segmented_none_of(first, test_detail::make_sentinel(last), equals_val(20))); BOOST_TEST(!segmented_none_of(first, test_detail::make_sentinel(last), equals_val(50))); BOOST_TEST(segmented_none_of(first, test_detail::make_sentinel(last), is_negative())); } void test_none_of_single_segment_seg2_inner_multi() { test_detail::seg_vector inner; int a1[] = {10, 20, 30}; int a2[] = {40, 50, 60, -99}; inner.add_segment_range(a1, a1 + 3); inner.add_segment_range(a2, a2 + 4); test_detail::seg2_vector sv2; sv2.add_segment(inner); typedef test_detail::seg2_vector::iterator iter_t; const iter_t first = test_detail::iter_at(sv2, 1); const iter_t last = test_detail::iter_at(sv2, 6); BOOST_TEST(!segmented_none_of(first, last, equals_val(20))); BOOST_TEST(!segmented_none_of(first, last, equals_val(40))); BOOST_TEST(!segmented_none_of(first, last, equals_val(60))); BOOST_TEST(segmented_none_of(first, last, equals_val(10))); BOOST_TEST(segmented_none_of(first, last, is_negative())); } void test_none_of_single_segment_seg2_single_inner() { test_detail::seg_vector inner; int a[] = {10, 20, 30, 40, 50, 60, -99}; inner.add_segment_range(a, a + 7); test_detail::seg2_vector sv2; sv2.add_segment(inner); typedef test_detail::seg2_vector::iterator iter_t; const iter_t first = test_detail::iter_at(sv2, 1); const iter_t last = test_detail::iter_at(sv2, 5); BOOST_TEST(!segmented_none_of(first, last, equals_val(20))); BOOST_TEST(!segmented_none_of(first, last, equals_val(50))); BOOST_TEST(segmented_none_of(first, last, equals_val(35))); BOOST_TEST(segmented_none_of(first, last, equals_val(10))); BOOST_TEST(segmented_none_of(first, last, is_negative())); } // The whole suite instantiates the bidirectional category only; the forward // one is a different instantiation of every dispatch template. void test_none_of_single_segment_forward() { typedef test_detail::seg_vector cont_t; typedef cont_t::iterator iter_t; cont_t sv; int a[] = {10, 20, 30, 40, 50, 60, -99}; sv.add_segment_range(a, a + 7); const iter_t whole_last = test_detail::iter_at(sv, 6); BOOST_TEST(!segmented_none_of(sv.begin(), whole_last, equals_val(10))); BOOST_TEST(!segmented_none_of(sv.begin(), whole_last, equals_val(60))); BOOST_TEST(segmented_none_of(sv.begin(), whole_last, is_negative())); const iter_t first = test_detail::iter_at(sv, 1); const iter_t last = test_detail::iter_at(sv, 5); BOOST_TEST(!segmented_none_of(first, last, equals_val(20))); BOOST_TEST(!segmented_none_of(first, last, equals_val(50))); BOOST_TEST(segmented_none_of(first, last, equals_val(10))); BOOST_TEST(segmented_none_of(first, last, equals_val(60))); } // Forward category, multi-segment, with the hit in an earlier segment and no // hit in the last one: the last-segment call must not discard it. void test_none_of_forward_hit_before_last_segment() { typedef test_detail::seg_vector cont_t; typedef cont_t::iterator iter_t; cont_t sv; int a1[] = {10, 20, 30}; int a2[] = {40, 50}; int a3[] = {60, 70, 80}; sv.add_segment_range(a1, a1 + 3); sv.add_segment_range(a2, a2 + 2); sv.add_segment_range(a3, a3 + 3); const iter_t last = test_detail::iter_at(sv, 7); BOOST_TEST(!segmented_none_of(sv.begin(), last, equals_val(20))); BOOST_TEST(!segmented_none_of(sv.begin(), last, equals_val(40))); BOOST_TEST(segmented_none_of(sv.begin(), last, equals_val(80))); } ////////////////////////////////////////////////////////////////////////////// // Predicate application count. // // [alg.none.of] mandates "At most last - first applications of the predicate". // The lower bound is not in the standard but follows from the answer: false // cannot be returned without having applied pred to every element up to and // including the first hit, and true cannot be returned without having applied // it to all of them. Bracketing the count catches an element retested when // the scan crosses a segment boundary. ////////////////////////////////////////////////////////////////////////////// template struct none_of_count_check { Pred pred; explicit none_of_count_check(Pred p) : pred(p) {} template void operator()(Cont& c, std::size_t n, const char* spec) const { const boost::container::vector flat = test_detail::flatten_n_ints(c, n); std::size_t needed = n; for(std::size_t i = 0; i != n; ++i) if(pred(flat[i])) { needed = i + 1u; break; } test_detail::op_counter calls; segmented_none_of(c.begin(), test_detail::iter_at(c, n), test_detail::counting_pred(calls, pred)); BOOST_TEST(calls.n <= n); BOOST_TEST(calls.n >= needed); BOOST_TEST(spec != 0); } }; template void run_none_of_count_shapes(const int* vals, std::size_t n, Pred pred) { test_detail::for_each_shape_all(vals, n, -999, none_of_count_check(pred)); test_detail::for_each_shape_all_fwd(vals, n, -999, none_of_count_check(pred)); } void test_none_of_predicate_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 v = 0; v <= n + 1u; ++v) run_none_of_count_shapes(vals, n, equals_val((v <= n) ? int(v) : -999)); run_none_of_count_shapes(vals, n, multiple_of(1)); run_none_of_count_shapes(vals, n, multiple_of(3)); run_none_of_count_shapes(vals, n, is_negative()); } } int main() { test_none_of_shape_matrix(); test_none_of_empty(); test_none_of_non_segmented(); test_none_of_sentinel_segmented(); test_none_of_sentinel_non_segmented(); test_none_of_single_segment_interior(); test_none_of_single_segment_sentinel(); test_none_of_single_segment_seg2_inner_multi(); test_none_of_single_segment_seg2_single_inner(); test_none_of_single_segment_forward(); test_none_of_forward_hit_before_last_segment(); test_none_of_predicate_count(); return boost::report_errors(); }