From 56268e7a180f98852532084d1131599856610af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 2 Feb 2026 12:59:07 +0100 Subject: [PATCH] Add experimental "segmented_vector" container, which is a single-ended version of deque. First implementation is suboptimal. --- bench/bench_vectors.cpp | 4 + include/boost/container/container_fwd.hpp | 7 + include/boost/container/options.hpp | 46 + .../boost/container/pmr/segmented_vector.hpp | 47 + include/boost/container/segmented_vector.hpp | 877 ++++++++++++++++++ test/CMakeLists.txt | 2 + test/segmented_vector_options_test.cpp | 106 +++ test/segmented_vector_test.cpp | 521 +++++++++++ 8 files changed, 1610 insertions(+) create mode 100644 include/boost/container/pmr/segmented_vector.hpp create mode 100644 include/boost/container/segmented_vector.hpp create mode 100644 test/segmented_vector_options_test.cpp create mode 100644 test/segmented_vector_test.cpp diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp index 8859b3e..5f95bf9 100644 --- a/bench/bench_vectors.cpp +++ b/bench/bench_vectors.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include //std::allocator @@ -446,6 +447,9 @@ void test_vectors_impl() vector_test_template< bc::deque >, Operation >(numit[i], numele[i], "deque ", bp); vector_test_template< bc::deque, typename bc::deque_options >::type >, Operation >(numit[i], numele[i], "deque(reserv) ", bp); + vector_test_template< bc::segmented_vector >, Operation >(numit[i], numele[i], "segmented_vec ", bp); + vector_test_template< bc::segmented_vector, + typename bc::deque_options >::type >, Operation >(numit[i], numele[i], "seg_vec(reserv)", bp); } std::cout << "---------------------------------\n---------------------------------\n"; } diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index b09342e..d6379b7 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -29,6 +29,8 @@ //! - boost::container::small_vector_base //! - boost::container::small_vector //! - boost::container::devector +//! - boost::container::deque +//! - boost::container::segmented_vector //! - boost::container::slist //! - boost::container::list //! - boost::container::set @@ -132,6 +134,11 @@ template class deque; +template +class segmented_vector; + template class list; diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index b68e605..c67e8fb 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -696,6 +696,52 @@ using deque_options_t = typename boost::container::deque_options::ty #endif +//////////////////////////////////////////////////////////////// +// +// +// OPTIONS FOR SEGMENTED_VECTOR CONTAINERS +// +// +//////////////////////////////////////////////////////////////// + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +struct segmented_vector_opt : public deque_opt +{}; + +typedef segmented_vector_opt<0u, 0u, void, false> segmented_vector_null_opt; + +#endif + +//! Helper metafunction to combine options into a single type to be used +//! by \c boost::container::deque. +//! Supported options are: \c boost::container::block_bytes, \c boost::container::block_size, +//! \c boost::container::stored_size and \c boost::container::reservable +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +struct segmented_vector_options + : deque_options +#else +template +struct segmented_vector_options + : deque_options +#endif +{}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +//! Helper alias metafunction to combine options into a single type to be used +//! by \c boost::container::deque. +template +using segmented_vector_options_t = typename boost::container::deque_options::type; + +#endif + + + + + //////////////////////////////////////////////////////////////// // // diff --git a/include/boost/container/pmr/segmented_vector.hpp b/include/boost/container/pmr/segmented_vector.hpp new file mode 100644 index 0000000..2cd5828 --- /dev/null +++ b/include/boost/container/pmr/segmented_vector.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025. 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_PMR_SEGMENTED_VECTOR_HPP +#define BOOST_CONTAINER_PMR_SEGMENTED_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +//! Warning: segmented_vector is EXPERIMENTAL, API and ABI will change. +template +using segmented_vector = boost::container::segmented_vector>; + +#endif + +//! A portable metafunction to obtain a segmented_vector +//! that uses a polymorphic allocator. +//! Warning: segmented_vector is EXPERIMENTAL, API and ABI will change. +template +struct segmented_vector_of +{ + typedef boost::container::segmented_vector + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_SEGMENTED_VECTOR_HPP diff --git a/include/boost/container/segmented_vector.hpp b/include/boost/container/segmented_vector.hpp new file mode 100644 index 0000000..82d3fc0 --- /dev/null +++ b/include/boost/container/segmented_vector.hpp @@ -0,0 +1,877 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025. 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_SEGMENTED_VECTOR_HPP +#define BOOST_CONTAINER_SEGMENTED_VECTOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace container { + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +//! A segmented vector is a sequence container that supports random access to elements, +//! constant time insertion and removal of elements at the end, and linear time +//! insertion and removal of elements in the middle. It uses the same segmented +//! (block-based) storage as deque but only allows growth at the back. +//! +//! This is the single-ended version of boost::container::deque: it provides +//! push_back, pop_back, emplace_back, etc., but does not provide push_front, +//! pop_front, or emplace_front. +//! +//! \tparam T The type of object that is stored in the segmented_vector +//! \tparam Allocator The allocator used for all internal memory management, use void +//! for the default allocator +//! \tparam Options A type produced from \c boost::container::segmented_vector_options. +//! +//! Warning: segmented_vector is EXPERIMENTAL, API and ABI will change. +template +#else +template +#endif +class segmented_vector : public deque_impl +{ +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + BOOST_COPYABLE_AND_MOVABLE(segmented_vector) + typedef deque_impl base_type; +#endif + + public: + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + + typedef T value_type; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::stored_allocator_type stored_allocator_type; + + using base_type::get_block_size; + static const std::size_t is_reservable = base_type::is_reservable; + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! Effects: Default constructs a segmented_vector. + //! + //! Throws: If allocator_type's default constructor throws. + //! + //! Complexity: Constant. + segmented_vector() + BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) + : base_type() + {} + + //! Effects: Constructs a segmented_vector taking the allocator as parameter. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + explicit segmented_vector(const allocator_type& a) BOOST_NOEXCEPT_OR_NOTHROW + : base_type(a) + {} + + //! Effects: Constructs a segmented_vector + //! and inserts n value initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's value initialization throws. + //! + //! Complexity: Linear to n. + explicit segmented_vector(size_type n) + : base_type(n) + {} + + //! Effects: Constructs a segmented_vector + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's default initialization or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + segmented_vector(size_type n, default_init_t) + : base_type(n, default_init) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts n value initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's value initialization throws. + //! + //! Complexity: Linear to n. + explicit segmented_vector(size_type n, const allocator_type& a) + : base_type(n, a) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's default initialization or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + segmented_vector(size_type n, default_init_t, const allocator_type& a) + : base_type(n, default_init, a) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + segmented_vector(size_type n, const value_type& value) + : base_type(n, value) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + segmented_vector(size_type n, const value_type& value, const allocator_type& a) + : base_type(n, value, a) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last). + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + segmented_vector(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_convertible::type* = 0 + #endif + ) + : base_type(first, last) + {} + + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last). + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + segmented_vector(InIt first, InIt last, const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_convertible::type* = 0 + #endif + ) + : base_type(first, last, a) + {} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Effects: Constructs a segmented_vector that will use a copy of allocator a + //! and inserts a copy of the range [il.begin(), il.end()). + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced std::initializer_list iterator throws. + //! + //! Complexity: Linear to the range [il.begin(), il.end()). + segmented_vector(std::initializer_list il, const allocator_type& a = allocator_type()) + : base_type(il, a) + {} +#endif + + //! Effects: Copy constructs a segmented_vector. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + segmented_vector(const segmented_vector& x) + : base_type(x) + {} + + //! Effects: Move constructor. Moves x's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + segmented_vector(BOOST_RV_REF(segmented_vector) x) BOOST_NOEXCEPT_OR_NOTHROW + : base_type(boost::move(static_cast(x))) + {} + + //! Effects: Copy constructs a segmented_vector using the specified allocator. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocation + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + segmented_vector(const segmented_vector& x, const allocator_type& a) + : base_type(x, a) + {} + + //! Effects: Move constructor using the specified allocator. + //! Moves x's resources to *this if a == allocator_type(). + //! Otherwise copies values from x to *this. + //! + //! Throws: If allocation or T's copy constructor throws. + //! + //! Complexity: Constant if a == x.get_allocator(), linear otherwise. + segmented_vector(BOOST_RV_REF(segmented_vector) x, const allocator_type& a) + : base_type(boost::move(static_cast(x)), a) + {} + + //! Effects: Destroys the segmented_vector. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~segmented_vector() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + segmented_vector& operator=(BOOST_COPY_ASSIGN_REF(segmented_vector) x) + { + base_type::operator=(static_cast(x)); + return *this; + } + + //! Effects: Move assignment. All x's values are transferred to *this. + //! + //! Throws: If allocator_traits_type::propagate_on_container_move_assignment + //! is false and (allocation throws or value_type's move constructor throws) + //! + //! Complexity: Constant if allocator_traits_type:: + //! propagate_on_container_move_assignment is true or + //! this->get_allocator() == x.get_allocator(). Linear otherwise. + segmented_vector& operator=(BOOST_RV_REF(segmented_vector) x) + BOOST_NOEXCEPT_IF(allocator_traits::propagate_on_container_move_assignment::value + || allocator_traits::is_always_equal::value) + { + base_type::operator=(BOOST_MOVE_BASE(base_type, x)); + return *this; + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Effects: Makes *this contain the same elements as il. + //! + //! Postcondition: this->size() == il.size(). *this contains a copy + //! of each of il's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in il. + segmented_vector& operator=(std::initializer_list il) + { + base_type::operator=(il); + return *this; + } + #endif + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Requires: The container must be "reservable" (is_reservable == true) + //! + //! Effects: If n is less than or equal to capacity() or the container is not reservable, + //! this call has no effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension. + void reserve(size_type n) + { + this->reserve_back(n); + } + + //! Effects: Returns the number of elements that can be inserted + //! at the back without allocating additional memory. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_NODISCARD size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + { + return this->back_capacity(); + } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD iterator begin() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD iterator end() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW; + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD bool empty() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD size_type size() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reference front(); + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reference front() const; + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the last element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reference back(); + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the last element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reference back() const; + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reference operator[](size_type n); + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reference operator[](size_type n) const; + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element from the beginning of the container. + //! + //! Throws: range_error if n >= size() + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD reference at(size_type n); + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element from the beginning of the container. + //! + //! Throws: range_error if n >= size() + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD const_reference at(size_type n) const; + + ////////////////////////////////////////////// + // + // allocator + // + ////////////////////////////////////////////// + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + BOOST_CONTAINER_NODISCARD allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_NODISCARD const stored_allocator_type& get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_NODISCARD stored_allocator_type& get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW; + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const value_type& value); + + //! Effects: Assigns the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InIt throws. + //! + //! Complexity: Linear to the distance [first, last). + template + void assign(InIt first, InIt last); + + //! Effects: Assigns the range [il.begin(), il.end()) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing std::initializer_list iterator throws. + //! + //! Complexity: Linear to il.size(). + void assign(std::initializer_list il); + + //! Effects: Erases all the elements of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the container. + void clear() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args); + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... at the end of the container. + //! + //! Returns: A reference to the created object. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time + template + reference emplace_back(BOOST_FWD_REF(Args)... args); + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator p, const value_type& x); + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with x's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator p, BOOST_RV_REF(value_type) x); + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Returns: an iterator to the first inserted element or pos if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator pos, size_type n, const value_type& x), + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to distance [first, last). + template + iterator insert(const_iterator pos, InIt first, InIt last); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [il.begin(), il.end()) range before pos. + //! + //! Returns: an iterator to the first inserted element or pos if il.begin() == il.end(). + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced std::initializer_list throws or T's copy constructor throws. + //! + //! Complexity: Linear to distance [il.begin(), il.end()). + iterator insert(const_iterator pos, std::initializer_list il); +#endif + + //! Effects: Erases the element at p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements between pos and the + //! last element (if pos is near the end) or the first element + //! if (pos is near the beginning). + //! Constant if pos is the first or the last element. + iterator erase(const_iterator p) BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and + //! last plus the elements between pos and the + //! last element (if pos is near the end) or the first element + //! if (pos is near the beginning). + iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Inserts a copy of x at the end of the container. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const value_type& x); + + //! Effects: Constructs a new element at the end of the container + //! and moves the resources of x to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(BOOST_RV_REF(value_type) x); + + //! Effects: Removes the last element from the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are value initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size); + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + //! + //! Note: Non-standard extension + void resize(size_type new_size, default_init_t); + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const value_type& x); + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(segmented_vector& x); + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator==(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) == static_cast(y); } + + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator!=(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) != static_cast(y); } + + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator<(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) < static_cast(y); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator>(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) > static_cast(y); } + + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator<=(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) <= static_cast(y); } + + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_NODISCARD inline + friend bool operator>=(const segmented_vector& x, const segmented_vector& y) + { return static_cast(x) >= static_cast(y); } + + //! Effects: x.swap(y) + //! + //! Complexity: Constant. + inline friend void swap(segmented_vector& x, segmented_vector& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) + { static_cast(x).swap(static_cast(y)); } + +}; + + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD +template +segmented_vector(InputIterator, InputIterator) -> segmented_vector::value_type>; +template +segmented_vector(InputIterator, InputIterator, Allocator const&) -> segmented_vector::value_type, Allocator>; +#endif + +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename segmented_vector::size_type erase(segmented_vector& c, const U& v) +{ + typename segmented_vector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename segmented_vector::size_type erase_if(segmented_vector& c, Pred pred) +{ + typename segmented_vector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + +} //namespace container { +} //namespace boost { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace boost { + +template +struct has_trivial_destructor_after_move > + : has_trivial_destructor_after_move > +{}; + +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#include + +#endif //#ifndef BOOST_CONTAINER_SEGMENTED_VECTOR_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ea02151..b98f91b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,6 +82,8 @@ boost_container_add_test(polymorphic_allocator_test polymorphic_allocator_test.c boost_container_add_test(resource_adaptor_test resource_adaptor_test.cpp) boost_container_add_test(scoped_allocator_adaptor_test scoped_allocator_adaptor_test.cpp) boost_container_add_test(scoped_allocator_usage_test scoped_allocator_usage_test.cpp) +boost_container_add_test(segmented_vector_options_test segmented_vector_options_test.cpp) +boost_container_add_test(segmented_vector_test segmented_vector_test.cpp) boost_container_add_test(set_test set_test.cpp) boost_container_add_test(slist_test slist_test.cpp) boost_container_add_test(small_vector_options_test small_vector_options_test.cpp) diff --git a/test/segmented_vector_options_test.cpp b/test/segmented_vector_options_test.cpp new file mode 100644 index 0000000..25c7a09 --- /dev/null +++ b/test/segmented_vector_options_test.cpp @@ -0,0 +1,106 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025. 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 +#include +#include + +using namespace boost::container; + +template +void test_stored_size_type_impl() +{ + #ifndef BOOST_NO_EXCEPTIONS + VectorType v; + typedef typename VectorType::size_type size_type; + size_type const max = Unsigned(-1); + v.resize(5); + BOOST_TEST_THROWS(v.resize(max+1), std::exception); + BOOST_TEST_THROWS(VectorType v2(max+1), std::exception); + #endif +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = segmented_vector_options_t< stored_size >; + #else + typedef typename segmented_vector_options + < stored_size >::type options_t; + #endif + + typedef segmented_vector > default_segmented_vector_t; + { + typedef segmented_vector, options_t> segmented_vector_t; + BOOST_CONTAINER_STATIC_ASSERT(sizeof(segmented_vector_t) < sizeof(default_segmented_vector_t)); + test_stored_size_type_impl(); + } + { + typedef segmented_vector, options_t> segmented_vector_t; + BOOST_CONTAINER_STATIC_ASSERT(sizeof(segmented_vector_t) < sizeof(default_segmented_vector_t)); + test_stored_size_type_impl(); + } +} + +void test_block_bytes() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = segmented_vector_options_t< block_bytes<128u> >; + #else + typedef segmented_vector_options< block_bytes<128u> >::type options_t; + #endif + typedef segmented_vector segmented_vector_t; + BOOST_TEST(segmented_vector_t::get_block_size() == 128u/sizeof(unsigned short)); +} + +void test_block_elements() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = segmented_vector_options_t< block_size<64> >; + #else + typedef segmented_vector_options< block_size<64> >::type options_t; + #endif + typedef segmented_vector segmented_vector_t; + BOOST_TEST(segmented_vector_t::get_block_size() == 64U); +} + +void test_reservable() +{ + { + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = segmented_vector_options_t< reservable >; + #else + typedef segmented_vector_options< reservable >::type options_t; + #endif + typedef segmented_vector segmented_vector_t; + BOOST_CONTAINER_STATIC_ASSERT(segmented_vector_t::is_reservable == true); + } + { + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = segmented_vector_options_t< reservable >; + #else + typedef segmented_vector_options< reservable >::type options_t; + #endif + typedef segmented_vector segmented_vector_t; + BOOST_CONTAINER_STATIC_ASSERT(segmented_vector_t::is_reservable == false); + } +} + +int main() +{ + test_block_bytes(); + test_block_elements(); + test_stored_size_type(); + test_stored_size_type(); + test_reservable(); + return ::boost::report_errors(); +} diff --git a/test/segmented_vector_test.cpp b/test/segmented_vector_test.cpp new file mode 100644 index 0000000..1738e96 --- /dev/null +++ b/test/segmented_vector_test.cpp @@ -0,0 +1,521 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +#include +#include + + +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include +#include +#include +#include +#include +#include "emplace_test.hpp" +#include "propagate_allocator_test.hpp" +#include "vector_test.hpp" +#include "default_init_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +#include + +using namespace boost::container; + +//Function to check if both sets are equal +// segmented_vector does not provide front operations; only back/middle tests +template +bool segmented_vector_copyable_only(V1 &, V2 &, dtl::false_type) +{ + return true; +} + +template +bool segmented_vector_copyable_only(V1 &cntc, V2 &stdc, dtl::true_type) +{ + typedef typename V1::value_type IntType; + std::size_t size = cntc.size(); + stdc.insert(stdc.end(), 50u, 1); + cntc.insert(cntc.end(), 50u, IntType(1)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + { + IntType move_me(1); + stdc.insert(stdc.begin()+std::ptrdiff_t(size)/2, 50u, 1); + cntc.insert(cntc.begin()+std::ptrdiff_t(size/2), 50u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + { + IntType move_me(2); + cntc.assign(cntc.size()/2, boost::move(move_me)); + stdc.assign(stdc.size()/2, 2); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + { + IntType move_me(1); + stdc.clear(); + cntc.clear(); + stdc.insert(stdc.begin(), 50u, 1); + cntc.insert(cntc.begin(), 50u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + stdc.insert(stdc.begin()+20, 50u, 1); + cntc.insert(cntc.begin()+20, 50u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + stdc.insert(stdc.begin()+20, 20u, 1); + cntc.insert(cntc.begin()+20, 20u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + { + IntType move_me(1); + stdc.clear(); + cntc.clear(); + stdc.insert(stdc.end(), 50u, 1); + cntc.insert(cntc.end(), 50u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + stdc.insert(stdc.end()-20, 50u, 1); + cntc.insert(cntc.end()-20, 50u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + stdc.insert(stdc.end()-20, 20u, 1); + cntc.insert(cntc.end()-20, 20u, boost::move(move_me)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + + return true; +} + +//Test recursive structures +class recursive_deque +{ +public: + + recursive_deque (const recursive_deque &x) + : deque_(x.deque_) + {} + + recursive_deque & operator=(const recursive_deque &x) + { this->deque_ = x.deque_; return *this; } + + segmented_vector deque_; + segmented_vector::iterator it_; + segmented_vector::const_iterator cit_; + segmented_vector::reverse_iterator rit_; + segmented_vector::const_reverse_iterator crit_; +}; + +bool do_recursive_deque_test() +{ + //Test for recursive types + { + segmented_vector recursive_deque_deque; + } + + { + //Now test move semantics + segmented_vector original; + segmented_vector move_ctor(boost::move(original)); + segmented_vector move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + return true; +} + +template +bool do_test() +{ + typedef typename deque_options >::type Options; + { + typedef segmented_vector MyCnt; + ::boost::movelib::unique_ptr const pcntc = ::boost::movelib::make_unique(); + pcntc->erase(pcntc->cbegin(), pcntc->cend()); + } + + //Alias deque types + typedef segmented_vector MyCnt; + typedef std::vector MyStd; + const int max = 100; + { + ::boost::movelib::unique_ptr const pcntc = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdc = ::boost::movelib::make_unique(); + MyCnt &cntc = *pcntc; + MyStd &stdc = *pstdc; + for(int i = 0; i < max*100; ++i){ + IntType move_me(i); + cntc.insert(cntc.end(), boost::move(move_me)); + stdc.insert(stdc.end(), i); + if(!test::CheckEqualContainers(cntc, stdc)) + return false; + } + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.clear(); + stdc.clear(); + + for(int i = 0; i < max*100; ++i){ + IntType move_me(i); + cntc.push_back(boost::move(move_me)); + stdc.push_back(i); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + typename MyCnt::iterator it; + typename MyCnt::const_iterator cit = it; + (void)cit; + + cntc.erase(cntc.begin()++); + stdc.erase(stdc.begin()++); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.erase(cntc.begin()++)); + stdc.erase(stdc.erase(stdc.begin()++)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.erase(cntc.begin()+3)); + stdc.erase(stdc.erase(stdc.begin()+3)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.erase(cntc.end()-2)); + stdc.erase(stdc.erase(stdc.end()-2)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.erase(cntc.end()-4)); + stdc.erase(stdc.erase(stdc.end()-4)); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.begin()); + stdc.erase(stdc.begin()); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + cntc.erase(cntc.end()-1); + stdc.erase(stdc.end()-1); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me (-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + cntc.insert(cntc.end() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stdc.insert(stdc.end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + for(int i = 0; i < 50; ++i){ + IntType move_me (i); + aux_vect[i] = boost::move(move_me); + } + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + cntc.insert(cntc.begin()+std::ptrdiff_t(cntc.size()) + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stdc.insert(stdc.begin()+std::ptrdiff_t(stdc.size()), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + for(int i = 0, j = static_cast(cntc.size()); i < j; ++i){ + cntc.erase(cntc.begin()); + stdc.erase(stdc.begin()); + } + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + cntc.insert(cntc.begin() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stdc.insert(stdc.begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntc, stdc)) return false; + } + + if(!segmented_vector_copyable_only(cntc, stdc + ,dtl::bool_::value>())){ + return false; + } + + cntc.erase(cntc.begin()); + stdc.erase(stdc.begin()); + + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + for(int i = 0; i < max; ++i){ + IntType move_me(i); + cntc.insert(cntc.begin(), boost::move(move_me)); + stdc.insert(stdc.begin(), i); + } + if(!test::CheckEqualContainers(cntc, stdc)) return false; + + //Test insertion from list + { + std::list l(50, int(1)); + cntc.insert(cntc.begin(), l.begin(), l.end()); + stdc.insert(stdc.begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(cntc, stdc)) return 1; + cntc.assign(l.begin(), l.end()); + stdc.assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(cntc, stdc)) return 1; + } + + cntc.resize(100); + stdc.resize(100); + if(!test::CheckEqualContainers(cntc, stdc)) return 1; + + cntc.resize(200); + stdc.resize(200); + if(!test::CheckEqualContainers(cntc, stdc)) return 1; + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //Check Constructor Template Auto Deduction + { + auto gold = MyStd{ 1, 2, 3 }; + auto test = segmented_vector(gold.begin(), gold.end()); + if(!test::CheckEqualContainers(gold, test)) return false; + } + { + auto gold = MyStd{ 1, 2, 3 }; + auto test = segmented_vector(gold.begin(), gold.end(), new_allocator()); + if(!test::CheckEqualContainers(gold, test)) return false; + } +#endif + + std::cout << std::endl << "Test OK!" << std::endl; + return true; +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef segmented_vector< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + , typename deque_options >::type + > type; + }; +}; + +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; + + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + return 0; +} + +template +struct char_holder +{ + char chars[N]; +}; + +bool do_test_default_block_size() +{ + //Check power of two sizes by default + BOOST_TEST(segmented_vector >::get_block_size() == 16*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 16*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 8*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 8*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 8*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 8*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 4*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + BOOST_TEST(segmented_vector >::get_block_size() == 2*sizeof(void*)); + //Minimal 8 elements + BOOST_TEST(segmented_vector >::get_block_size() == 8u); + return 0 == boost::report_errors(); +} + +struct boost_container_segmented_vector; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::segmented_vector type; + }; +}; + +}}} //namespace boost::container::test + +int main () +{ + if(!do_recursive_deque_test()) + return 1; + + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + //Default block size + if(!do_test_default_block_size()) + return 1; + + //Test non-copy-move operations (back only; no emplace_front) + { + segmented_vector d; + d.emplace_back(); + d.emplace_back(1); + d.resize(10); + d.resize(1); + } + + //////////////////////////////////// + // Allocator implementations + //////////////////////////////////// + // std:allocator + if(test_cont_variants< std::allocator, false >()){ + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + + // boost::container::allocator + if(test_cont_variants< allocator, true >()){ + std::cerr << "test_cont_variants< allocator > failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< segmented_vector > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + // segmented_vector does not provide front operations (emplace_front, push_front, pop_front) + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + + if(!boost::container::test::test_emplace + < segmented_vector, Options>()) + return 1; + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Initializer lists testing + //////////////////////////////////// + if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for + < boost::container::segmented_vector >()) { + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::segmented_vector cont_int; + for(std::size_t i = 1; i <= 10000; i*=10){ + cont_int a; + for (int j = 0; j < (int)i; ++j) + a.push_back((int)j); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::segmented_vector cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + BOOST_CONTAINER_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); + } + // std::allocator + { + typedef boost::container::segmented_vector > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + BOOST_CONTAINER_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) + , "has_trivial_destructor_after_move(std::allocator) test failed"); + } + + return 0; +}