From f309f82a8f6fd1a3603f912fc62e7deb417dcfad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 19 Feb 2013 21:35:46 +0000 Subject: [PATCH] Added experimental static_vector first sketch [SVN r83036] --- include/boost/container/detail/utilities.hpp | 53 + include/boost/container/static_vector.hpp | 1040 ++++++++++++++++++ include/boost/container/vector.hpp | 834 +++++++++----- proj/vc7ide/static_vector_test.vcproj | 139 +++ test/movable.hpp | 92 ++ test/static_vector_test.cpp | 803 ++++++++++++++ test/static_vector_test.hpp | 99 ++ 7 files changed, 2805 insertions(+), 255 deletions(-) create mode 100644 include/boost/container/static_vector.hpp create mode 100644 proj/vc7ide/static_vector_test.vcproj create mode 100644 test/movable.hpp create mode 100644 test/static_vector_test.cpp create mode 100644 test/static_vector_test.hpp diff --git a/include/boost/container/detail/utilities.hpp b/include/boost/container/detail/utilities.hpp index 23489db..02141a4 100644 --- a/include/boost/container/detail/utilities.hpp +++ b/include/boost/container/detail/utilities.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -700,6 +701,58 @@ inline I move_n_source(I f, typename std::iterator_traits::difference_type n, return f; } +////////////////////////////////////////////////////////////////////////////// +// +// destroy_n +// +////////////////////////////////////////////////////////////////////////////// + +template + // I models InputIterator +inline void destroy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n + ,typename boost::container::container_detail::enable_if_c + < !boost::has_trivial_destructor::value_type>::value >::type* = 0) +{ + while(n--){ + allocator_traits::destroy(a, container_detail::addressof(*f++)); + } +} + +template + // I models InputIterator +inline void destroy_alloc_n(A &, I, typename std::iterator_traits::difference_type + ,typename boost::container::container_detail::enable_if_c + < boost::has_trivial_destructor::value_type>::value >::type* = 0) +{} + +////////////////////////////////////////////////////////////////////////////// +// +// deep_swap_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +void deep_swap_alloc_n(A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typename allocator_traits::size_type n = 0; + typedef typename allocator_traits::value_type value_type; + for (; n != n_i ; ++short_range_f, ++large_range_f, ++n){ + //boost::swap(*first_sm, *first_la); // may throw + value_type temp(boost::move(*short_range_f)); // may throw + *short_range_f = boost::move(*large_range_f); // may throw + *large_range_f = boost::move(temp); // may throw + } + uninitialized_move_alloc_n(a, large_range_f, n_j - n, short_range_f); // may throw + destroy_alloc_n(a, large_range_f, n_j - n); +} + } //namespace container { } //namespace boost { diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp new file mode 100644 index 0000000..428c7de --- /dev/null +++ b/include/boost/container/static_vector.hpp @@ -0,0 +1,1040 @@ +// Boost.Container static_vector +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// +// Use, modification and distribution is subject to 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) + +#ifndef BOOST_CONTAINER_STATIC_VECTOR_HPP +#define BOOST_CONTAINER_STATIC_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#include +#include + +namespace boost { namespace container { + +/** + * @defgroup static_vector_non_member static_vector non-member functions + */ + +/** + * @brief A variable-size array container with fixed capacity. + * + * static_vector is a sequence container like boost::container::vector with contiguous storage that can + * change in size, along with the static allocation, low overhead, and fixed capacity of boost::array. + * + * A static_vector is a sequence that supports random access to elements, constant time insertion and + * removal of elements at the end, and linear time insertion and removal of elements at the beginning or + * in the middle. The number of elements in a static_vector may vary dynamically up to a fixed capacity + * because elements are stored within the object itself similarly to an array. However, objects are + * initialized as they are inserted into static_vector unlike C arrays or std::array which must construct + * all elements on instantiation. The behavior of static_vector enables the use of statically allocated + * elements in cases with complex object lifetime requirements that would otherwise not be trivially + * possible. + * + * @par Error Handling + * Insertion beyond the capacity and out of bounds errors results in calling throw_bad_alloc(). + * The reason for this is because unlike vectors, static_vector does not perform allocation. + * + * @tparam Value The type of element that will be stored. + * @tparam Capacity The maximum number of elements static_vector can store, fixed at compile time. + */ + + +namespace container_detail { + +template +class static_storage_allocator +{ + public: + typedef T value_type; + + T* internal_storage() const + { return const_cast(static_cast(static_cast(&storage))); } + + T* internal_storage() + { return static_cast(static_cast(&storage)); } + + static const std::size_t internal_capacity = N; + + typedef boost::container::container_detail::version_type version; + + friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) + { return false; } + + friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) + { return true; } + + private: + typename boost::aligned_storage + ::value>::type storage; +}; + +} //namespace container_detail { + + +template +class static_vector + : public vector > +{ + typedef vector > base_t; + + BOOST_COPYABLE_AND_MOVABLE(static_vector) + + template + friend class static_vector; + +public: + //! @brief The type of elements stored in the container. + typedef typename base_t::value_type value_type; + //! @brief The unsigned integral type used by the container. + typedef typename base_t::size_type size_type; + //! @brief The pointers difference type. + typedef typename base_t::difference_type difference_type; + //! @brief The pointer type. + typedef typename base_t::pointer pointer; + //! @brief The const pointer type. + typedef typename base_t::const_pointer const_pointer; + //! @brief The value reference type. + typedef typename base_t::reference reference; + //! @brief The value const reference type. + typedef typename base_t::const_reference const_reference; + //! @brief The iterator type. + typedef typename base_t::iterator iterator; + //! @brief The const iterator type. + typedef typename base_t::const_iterator const_iterator; + //! @brief The reverse iterator type. + typedef typename base_t::reverse_iterator reverse_iterator; + //! @brief The const reverse iterator. + typedef typename base_t::const_reverse_iterator const_reverse_iterator; + + //! @brief Constructs an empty static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static_vector() + : base_t() + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a static_vector containing count default constructed Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! + //! @par Complexity + //! Linear O(N). + explicit static_vector(size_type count) + : base_t(count) + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a static_vector containing count copies of value. + //! + //! @param count The number of copies of a values that will be contained in the container. + //! @param value The value which will be used to copy construct values. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(size_type count, value_type const& value) + : base_t(count, value) + {} + + //! @pre + //! @li distance(first, last) <= capacity() + //! @li Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Constructs a static_vector containing copy of a range [first, last). + //! + //! @param first The iterator to the first element in range. + //! @param last The iterator to the one after the last element in range. + //! + //! @par Throws + //! If Value's constructor taking a dereferenced Iterator throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(Iterator first, Iterator last) + : base_t(first, last) + {} + + //! @brief Constructs a copy of other static_vector. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(static_vector const& other) + : base_t(other) + {} + + //! @pre other.size() <= capacity(). + //! + //! @brief Constructs a copy of other static_vector. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(static_vector const& other) : base_t(other) {} + + //! @brief Copy assigns Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector & operator=(BOOST_COPY_ASSIGN_REF(static_vector) other) + { + base_t::operator=(static_cast(other)); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Copy assigns Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_RVALUE_REFERENCES) + static_vector & operator=(::boost::rv< static_vector > const& other) +#else + static_vector & operator=(static_vector const& other) +#endif + { + base_t::operator=(static_cast const&>(other)); + return *this; + } + + //! @brief Move constructor. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(BOOST_RV_REF(static_vector) other) + : base_t(boost::move(static_cast(other))) + {} + + //! @pre other.size() <= capacity() + //! + //! @brief Move constructor. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(BOOST_RV_REF_BEG static_vector BOOST_RV_REF_END other) + : base_t(boost::move(static_cast::base_t&>(other))) + {} + + //! @brief Move assignment. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector & operator=(BOOST_RV_REF(static_vector) other) + { + base_t::operator=(boost::move(static_cast(other))); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Move assignment. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector & operator=(BOOST_RV_REF_BEG static_vector BOOST_RV_REF_END other) + { + base_t::operator=(boost::move(static_cast::base_t&>(other))); + return *this; + } + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~static_vector(); + + //! @brief Swaps contents of the other static_vector and this one. + //! + //! @param other The static_vector which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + void swap(static_vector & other); + + //! @pre other.size() <= capacity() && size() <= other.capacity() + //! + //! @brief Swaps contents of the other static_vector and this one. + //! + //! @param other The static_vector which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void swap(static_vector & other); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are default constructed. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are copy constructed from value. + //! + //! @param count The number of elements which will be stored in the container. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count, value_type const& value); + + //! @pre count <= capacity() + //! + //! @brief This call has no effect because the Capacity of this container is constant. + //! + //! @param count The number of elements which the container should be able to contain. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Linear O(N). + void reserve(size_type count); + + //! @pre size() < capacity() + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(BOOST_RV_REF(value_type) value); + + //! @pre !empty() + //! + //! @brief Destroys last value and decreases the size. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + void pop_back(); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a copy of element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a move-constructed element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, BOOST_RV_REF(value_type) value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() + count <= capacity() + //! + //! @brief Inserts a count copies of value at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param count The number of new elements which will be inserted. + //! @param value The value used to copy construct new elements. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator insert(iterator position, size_type count, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li distance(first, last) <= capacity() + //! @li \c Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Inserts a copy of a range [first, last) at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param first The iterator to the first element of a range used to construct new elements. + //! @param last The iterator to the one after the last element of a range used to construct new elements. + //! + //! @par Throws + //! @li If Value's constructor and assignment taking a dereferenced \c Iterator. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + iterator insert(iterator position, Iterator first, Iterator last); + + //! @pre \c position must be a valid iterator of \c *this in range [begin(), end()) + //! + //! @brief Erases Value from position. + //! + //! @param position The position of the element which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator position); + + //! @pre + //! @li \c first and \c last must define a valid range + //! @li iterators must be in range [begin(), end()] + //! + //! @brief Erases Values from a range [first, last). + //! + //! @param first The position of the first element of a range which will be erased from the container. + //! @param last The position of the one after the last element of a range which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator first, iterator last); + + //! @pre distance(first, last) <= capacity() + //! + //! @brief Assigns a range [first, last) of Values to this container. + //! + //! @param first The iterator to the first element of a range used to construct new content of this container. + //! @param last The iterator to the one after the last element of a range used to construct new content of this container. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void assign(Iterator first, Iterator last); + + //! @pre count <= capacity() + //! + //! @brief Assigns a count copies of value to this container. + //! + //! @param count The new number of elements which will be container in the container. + //! @param value The value which will be used to copy construct the new content. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + void assign(size_type count, value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... in the end of the container. + //! + //! @param args The arguments of the constructor of the new element which will be created at the end of the container. + //! + //! @par Throws + //! If in-place constructor throws or Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + template + void emplace_back(Args &&...args); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()] + //! @li size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... before position + //! + //! @param position The position at which new elements will be inserted. + //! @param args The arguments of the constructor of the new element. + //! + //! @par Throws + //! If in-place constructor throws or if Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + template + iterator emplace(iterator position, Args &&...args); + + //! @brief Removes all elements from the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + void clear(); + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + reference at(size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference at(size_type i) const; + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference operator[](size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference operator[](size_type i) const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the first element. + //! + //! @return reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference front(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference front() const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the last element. + //! + //! @return reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference back(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference back() const; + + //! @brief Pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + Value * data(); + + //! @brief Const pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const Value * data() const; + + //! @brief Returns iterator to the first element. + //! + //! @return iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator begin(); + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator begin() const; + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cbegin() const; + + //! @brief Returns iterator to the one after the last element. + //! + //! @return iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator end(); + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator end() const; + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cend() const; + + //! @brief Returns reverse iterator to the first element of the reversed container. + //! + //! @return reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rbegin(); + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rbegin() const; + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crbegin() const; + + //! @brief Returns reverse iterator to the one after the last element of the reversed container. + //! + //! @return reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rend(); + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rend() const; + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crend() const; + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type capacity(); + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type max_size(); + + //! @brief Returns the number of stored elements. + //! + //! @return Number of elements contained in the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + size_type size() const; + + //! @brief Queries if the container contains elements. + //! + //! @return true if the number of elements contained in the + //! container is equal to 0. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + bool empty() const; + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}; + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! @brief Checks if contents of two static_vectors are equal. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if containers have the same size and elements in both containers are equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator== (static_vector const& x, static_vector const& y); + +//! @brief Checks if contents of two static_vectors are not equal. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if containers have different size or elements in both containers are not equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator!= (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if x compares lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator< (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if y compares lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator> (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if y don't compare lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator<= (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if x don't compare lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator>= (static_vector const& x, static_vector const& y); + +//! @brief Swaps contents of two static_vectors. +//! +//! This function calls static_vector::swap(). +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @par Complexity +//! Linear O(N). +template +inline void swap(static_vector & x, static_vector & y); + +#else + +template +inline void swap(static_vector & x, static_vector & y) +{ + x.swap(y); +} + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_STATIC_VECTOR_HPP diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 37fdc2a..859445c 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -74,7 +74,10 @@ class vector_const_iterator Pointer m_ptr; public: - Pointer get_ptr() const BOOST_CONTAINER_NOEXCEPT + const Pointer &get_ptr() const BOOST_CONTAINER_NOEXCEPT + { return m_ptr; } + + Pointer &get_ptr() BOOST_CONTAINER_NOEXCEPT { return m_ptr; } explicit vector_const_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT @@ -247,7 +250,12 @@ struct vector_value_traits }; //!This struct deallocates and allocated memory -template +template < class Allocator + , class AllocatorVersion = container_detail::integral_constant + < unsigned + , boost::container::container_detail::version::value + > + > struct vector_alloc_holder : public Allocator { @@ -259,11 +267,6 @@ struct vector_alloc_holder typedef typename allocator_traits_type::pointer pointer; typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::value_type value_type; - typedef vector_value_traits value_traits; - typedef container_detail::integral_constant allocator_v1; - typedef container_detail::integral_constant allocator_v2; - typedef container_detail::integral_constant::value> alloc_version; //Constructor, does not throw vector_alloc_holder() @@ -279,19 +282,19 @@ struct vector_alloc_holder //Constructor, does not throw template - explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type capacity) + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() { m_start = this->allocation_command - (allocate_new, capacity, capacity, m_capacity, m_start).first; + (allocate_new, cap, cap, m_capacity, m_start).first; } //Constructor, does not throw - explicit vector_alloc_holder(size_type capacity) + explicit vector_alloc_holder(size_type cap) : Allocator(), m_start(), m_size(), m_capacity() { m_start = this->allocation_command - (allocate_new, capacity, capacity, m_capacity, m_start).first; + (allocate_new, cap, cap, m_capacity, m_start).first; } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT @@ -302,26 +305,16 @@ struct vector_alloc_holder holder.m_size = holder.m_capacity = 0; } - void first_allocation(size_type capacity) + void first_allocation(size_type cap) { m_start = this->allocation_command - (allocate_new, capacity, capacity, m_capacity, m_start).first; - } - - template - void first_allocation_fill(Proxy proxy, size_type n) - { - //Copy first new elements in pos - proxy.uninitialized_copy_n_and_update - (container_detail::to_raw_pointer(this->m_start), n); - this->m_size = n; + (allocate_new, cap, cap, m_capacity, m_start).first; } //Destructor ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT { if(this->m_capacity){ - this->destroy_n(container_detail::to_raw_pointer(this->m_start), this->m_size); this->alloc().deallocate(this->m_start, this->m_capacity); } } @@ -349,7 +342,7 @@ struct vector_alloc_holder size_type m_size; size_type m_capacity; - void swap_members(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT + void swap(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { container_detail::do_swap(this->m_start, x.m_start); container_detail::do_swap(this->m_size, x.m_size); @@ -381,25 +374,142 @@ struct vector_alloc_holder } } - void destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT + const pointer &start() const { return m_start; } + const size_type &capacity() const { return m_capacity; } + void start(const pointer &p) { m_start = p; } + void capacity(const size_type &c) { m_capacity = c; } +}; + +//!This struct deallocates and allocated memory +template +struct vector_alloc_holder > + : public Allocator +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) + + public: + typedef boost::container::allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + typedef typename allocator_traits_type::size_type size_type; + typedef typename allocator_traits_type::value_type value_type; + + template + friend struct vector_alloc_holder; + + //Constructor, does not throw + vector_alloc_holder() + BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) + : Allocator(), m_size(0) + {} + + //Constructor, does not throw + template + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT + : Allocator(boost::forward(a)), m_size(0) + {} + + //Constructor, does not throw + template + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) + : Allocator(boost::forward(a)), m_size() { - if(!value_traits::trivial_dctr) - allocator_traits_type::destroy(this->alloc(), p); + this->first_allocation(cap); } - void destroy_n(value_type* p, size_type n) BOOST_CONTAINER_NOEXCEPT + //Constructor, does not throw + explicit vector_alloc_holder(size_type cap) + : Allocator(), m_size() { - if(!value_traits::trivial_dctr){ - for(; n--; ++p){ - allocator_traits_type::destroy(this->alloc(), p); - } + this->first_allocation(cap); + } + + vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) + : Allocator(boost::move(static_cast(holder))) + , m_size() + { + this->priv_move_construct_impl(holder); + } + + template + vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder BOOST_RV_REF_END holder) + : Allocator() + , m_size() + { + this->priv_move_construct_impl(holder); + } + + void first_allocation(size_type cap) + { + if(cap > Allocator::internal_capacity){ + throw_bad_alloc(); } } - void destroy_all() BOOST_CONTAINER_NOEXCEPT + //Destructor + ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT + {} + + void swap(vector_alloc_holder &x) { - this->destroy_n(container_detail::to_raw_pointer(this->m_start), this->m_size); - this->m_size = 0; + this->priv_swap_members_impl(x); + } + + template + void swap(vector_alloc_holder &x) + { + if(this->m_size > x.capacity() || x.m_size > this->capacity()){ + throw_bad_alloc(); + } + this->priv_swap_members_impl(x); + } + + void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT + { //Containers with version 0 allocators can't be moved without move elements one by one + throw_bad_alloc(); + } + + Allocator &alloc() BOOST_CONTAINER_NOEXCEPT + { return *this; } + + const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT + { return *this; } + + void deallocate() BOOST_CONTAINER_NOEXCEPT + {} + + pointer start() const { return Allocator::internal_storage(); } + size_type capacity() const { return Allocator::internal_capacity; } + size_type m_size; + + private: + + template + void priv_move_construct_impl(vector_alloc_holder &holder) + { //Containers with version 0 allocators can't be moved + const size_type n = holder.m_size; + this->first_allocation(n); + //Copy first new elements in pos + container_detail::move_insert_range_proxy proxy + (this->alloc(), container_detail::to_raw_pointer(holder.start())); + proxy.uninitialized_copy_n_and_update + (container_detail::to_raw_pointer(this->start()), n); + this->m_size = n; + } + + template + void priv_swap_members_impl(vector_alloc_holder &x) + { + value_type *const first_this = container_detail::to_raw_pointer(this->start()); + value_type *const first_x = container_detail::to_raw_pointer(x.start()); + + if(this->m_size < x.m_size){ + deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); + } + else{ + deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); + } + container_detail::do_swap(this->m_size, x.m_size); } }; @@ -424,6 +534,8 @@ class vector /// @cond typedef container_detail::vector_alloc_holder base_t; typedef allocator_traits allocator_traits_type; + template + friend class vector; /// @endcond public: ////////////////////////////////////////////// @@ -451,11 +563,14 @@ class vector BOOST_COPYABLE_AND_MOVABLE(vector) typedef container_detail::vector_value_traits value_traits; - typedef typename base_t::allocator_v1 allocator_v1; - typedef typename base_t::allocator_v2 allocator_v2; - typedef typename base_t::alloc_version alloc_version; + typedef container_detail::integral_constant allocator_v0; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + typedef container_detail::integral_constant + ::value > alloc_version; - typedef constant_iterator cvalue_iterator; + typedef constant_iterator cvalue_iterator; /// @endcond public: @@ -494,24 +609,50 @@ class vector explicit vector(size_type n) : m_holder(n) { - this->m_holder.first_allocation_fill + this->priv_first_allocation_fill (container_detail::insert_default_constructed_n_proxy (this->m_holder.alloc()), n); } - //! Effects: Constructs a vector that will use a copy of allocator a + //! Effects: Constructs a vector //! and inserts n copies of value. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to n. - vector(size_type n, const T& value, const allocator_type& a = allocator_type()) - : m_holder(a, n) + vector(size_type n, const T& value) + : m_holder(n) { - this->m_holder.first_allocation_fill + this->priv_first_allocation_fill (container_detail::insert_n_copies_proxy (this->m_holder.alloc(), value), n); } + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocation + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n, const T& value, const allocator_type& a) + : m_holder(a, n) + { + this->priv_first_allocation_fill + (container_detail::insert_n_copies_proxy (this->m_holder.alloc(), value), n); + } + + //! Effects: Constructs a vector + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or allocation + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last) + : m_holder() + { this->insert(this->cend(), first, last); } + //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the vector. //! @@ -520,7 +661,7 @@ class vector //! //! Complexity: Linear to the range [first, last). template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + vector(InIt first, InIt last, const allocator_type& a) : m_holder(a) { this->insert(this->cend(), first, last); } @@ -535,9 +676,9 @@ class vector vector(const vector &x) : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) { - this->m_holder.first_allocation_fill + this->priv_first_allocation_fill (container_detail::insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.m_start)), x.size()); + (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); } //! Effects: Move constructor. Moves mx's resources to *this. @@ -549,6 +690,22 @@ class vector : m_holder(boost::move(mx.m_holder)) {} + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If T's move constructor or allocation throws + //! + //! Complexity: Linear. + //! + //! Note: Non-standard extension + template + vector(BOOST_RV_REF_BEG vector BOOST_RV_REF_END mx) + : m_holder(boost::move(mx.m_holder)) + {} + + #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Copy constructs a vector using the specified allocator. //! //! Postcondition: x == *this. @@ -560,9 +717,9 @@ class vector vector(const vector &x, const allocator_type &a) : m_holder(a, x.size()) { - this->m_holder.first_allocation_fill + this->priv_first_allocation_fill (container_detail::insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.m_start)), x.size()); + (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); } //! Effects: Move constructor using the specified allocator. @@ -581,9 +738,9 @@ class vector else{ const size_type n = mx.size(); this->m_holder.first_allocation(n); - this->m_holder.first_allocation_fill + this->priv_first_allocation_fill (container_detail::move_insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.m_start)), n); + (this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start())), n); } } @@ -594,7 +751,10 @@ class vector //! //! Complexity: Linear to the number of elements. ~vector() BOOST_CONTAINER_NOEXCEPT - {} //vector_alloc_holder clears the data + { + destroy_alloc_n(this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + //vector_alloc_holder deallocates the data + } //! Effects: Makes *this contain the same elements as x. //! @@ -616,8 +776,8 @@ class vector this->shrink_to_fit(); } container_detail::assign_alloc(this_alloc, x_alloc, flag); - this->assign( container_detail::to_raw_pointer(x.m_holder.m_start) - , container_detail::to_raw_pointer(x.m_holder.m_start + x.m_holder.m_size)); + this->assign( container_detail::to_raw_pointer(x.m_holder.start()) + , container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)); } return *this; } @@ -641,7 +801,7 @@ class vector if(this_alloc == x_alloc){ //Destroy objects but retain memory in case x reuses it in the future this->clear(); - this->m_holder.swap_members(x.m_holder); + this->m_holder.swap(x.m_holder); //Move allocator if needed container_detail::bool_ flag; @@ -649,13 +809,33 @@ class vector } //If unequal allocators, then do a one by one move else{ - this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.m_start)) - , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.m_start + x.m_holder.m_size))); + this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) + , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size))); } } return *this; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If move constructor/assignment of T throws or allocation throws + //! + //! Complexity: Linear. + template + vector& operator=(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x) + { + this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) + , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size))); + return *this; + } + + #endif + //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or T's copy/move constructor/assignment or @@ -680,7 +860,9 @@ class vector if (first == last){ //There are no more elements in the sequence, erase remaining - this->erase(cur, this->cend()); + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + size_type n = static_cast(end_pos - container_detail::to_raw_pointer(cur.get_ptr())); + this->priv_destroy_last_n(n); } else{ //There are more elements in the range, insert the remaining ones @@ -737,7 +919,7 @@ class vector //! //! Complexity: Constant. iterator begin() BOOST_CONTAINER_NOEXCEPT - { return iterator(this->m_holder.m_start); } + { return iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the first element contained in the vector. //! @@ -745,7 +927,7 @@ class vector //! //! Complexity: Constant. const_iterator begin() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->m_holder.m_start); } + { return const_iterator(this->m_holder.start()); } //! Effects: Returns an iterator to the end of the vector. //! @@ -753,7 +935,7 @@ class vector //! //! Complexity: Constant. iterator end() BOOST_CONTAINER_NOEXCEPT - { return iterator(this->m_holder.m_start + this->m_holder.m_size); } + { return iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -805,7 +987,7 @@ class vector //! //! Complexity: Constant. const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->m_holder.m_start); } + { return const_iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -813,7 +995,7 @@ class vector //! //! Complexity: Constant. const_iterator cend() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->m_holder.m_start + this->m_holder.m_size); } + { return const_iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. @@ -871,15 +1053,15 @@ class vector //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - if (new_size < this->size()){ + const size_type sz = this->size(); + if (new_size < sz){ //Destroy last elements - this->erase(const_iterator(this->m_holder.m_start + new_size), this->end()); + this->priv_destroy_last_n(sz - new_size); } else{ const size_type n = new_size - this->size(); - this->reserve(new_size); container_detail::insert_default_constructed_n_proxy proxy(this->m_holder.alloc()); - this->priv_forward_range_insert(this->cend().get_ptr(), n, proxy); + this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } @@ -891,14 +1073,15 @@ class vector //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - pointer finish = this->m_holder.m_start + this->m_holder.m_size; - if (new_size < size()){ + const size_type sz = this->size(); + if (new_size < sz){ //Destroy last elements - this->erase(const_iterator(this->m_holder.m_start + new_size), this->end()); + this->priv_destroy_last_n(sz - new_size); } else{ - //Insert new elements at the end - this->insert(const_iterator(finish), new_size - this->size(), x); + const size_type n = new_size - this->size(); + container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } @@ -909,7 +1092,7 @@ class vector //! //! Complexity: Constant. size_type capacity() const BOOST_CONTAINER_NOEXCEPT - { return this->m_holder.m_capacity; } + { return this->m_holder.capacity(); } //! Effects: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. @@ -920,54 +1103,7 @@ class vector void reserve(size_type new_cap) { if (this->capacity() < new_cap){ - //There is not enough memory, allocate a new - //buffer or expand the old one. - bool same_buffer_start; - size_type real_cap = 0; - std::pair ret = - this->m_holder.allocation_command - (allocate_new | expand_fwd | expand_bwd, - new_cap, new_cap, real_cap, this->m_holder.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->m_holder.m_start == ret.first; - if(same_buffer_start){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->m_holder.m_capacity = real_cap; - } - - //If there is no forward expansion, move objects - else{ - //We will reuse insert code, so create a dummy input iterator - container_detail::insert_range_proxy, T*> - proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); - //Backwards (and possibly forward) expansion - if(alloc_version::value > 1 && ret.second){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->m_holder.m_start) - , 0 - , proxy); - } - //New buffer - else{ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->m_holder.m_start) - , 0 - , proxy); - } - } + this->priv_reserve(new_cap, alloc_version()); } } @@ -995,7 +1131,7 @@ class vector //! //! Complexity: Constant. reference front() BOOST_CONTAINER_NOEXCEPT - { return *this->m_holder.m_start; } + { return *this->m_holder.start(); } //! Requires: !empty() //! @@ -1006,7 +1142,7 @@ class vector //! //! Complexity: Constant. const_reference front() const BOOST_CONTAINER_NOEXCEPT - { return *this->m_holder.m_start; } + { return *this->m_holder.start(); } //! Requires: !empty() //! @@ -1017,7 +1153,7 @@ class vector //! //! Complexity: Constant. reference back() BOOST_CONTAINER_NOEXCEPT - { return this->m_holder.m_start[this->m_holder.m_size - 1]; } + { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: !empty() //! @@ -1028,7 +1164,7 @@ class vector //! //! Complexity: Constant. const_reference back() const BOOST_CONTAINER_NOEXCEPT - { return this->m_holder.m_start[this->m_holder.m_size - 1]; } + { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: size() > n. //! @@ -1039,7 +1175,7 @@ class vector //! //! Complexity: Constant. reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT - { return this->m_holder.m_start[n]; } + { return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1050,7 +1186,7 @@ class vector //! //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT - { return this->m_holder.m_start[n]; } + { return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1061,7 +1197,7 @@ class vector //! //! Complexity: Constant. reference at(size_type n) - { this->priv_check_range(n); return this->m_holder.m_start[n]; } + { this->priv_check_range(n); return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1072,7 +1208,7 @@ class vector //! //! Complexity: Constant. const_reference at(size_type n) const - { this->priv_check_range(n); return this->m_holder.m_start[n]; } + { this->priv_check_range(n); return this->m_holder.start()[n]; } ////////////////////////////////////////////// // @@ -1087,7 +1223,7 @@ class vector //! //! Complexity: Constant. T* data() BOOST_CONTAINER_NOEXCEPT - { return container_detail::to_raw_pointer(this->m_holder.m_start); } + { return container_detail::to_raw_pointer(this->m_holder.start()); } //! Returns: Allocator pointer such that [data(),data() + size()) is a valid range. //! For a non-empty vector, data() == &front(). @@ -1096,7 +1232,7 @@ class vector //! //! Complexity: Constant. const T * data() const BOOST_CONTAINER_NOEXCEPT - { return container_detail::to_raw_pointer(this->m_holder.m_start); } + { return container_detail::to_raw_pointer(this->m_holder.start()); } ////////////////////////////////////////////// // @@ -1115,16 +1251,16 @@ class vector template void emplace_back(Args &&...args) { - T* back_pos = container_detail::to_raw_pointer(this->m_holder.m_start) + this->m_holder.m_size; - if (this->m_holder.m_size < this->m_holder.m_capacity){ + T* back_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct(this->m_holder.alloc(), back_pos, ::boost::forward(args)...); ++this->m_holder.m_size; } else{ typedef container_detail::insert_emplace_proxy type; - this->priv_forward_range_insert - (back_pos, 1, type(this->m_holder.alloc(), ::boost::forward(args)...)); + this->priv_forward_range_insert_at_end + (1, type(this->m_holder.alloc(), ::boost::forward(args)...), alloc_version()); } } @@ -1143,8 +1279,8 @@ class vector { //Just call more general insert(pos, size, value) and return iterator typedef container_detail::insert_emplace_proxy type; - return this->priv_forward_range_insert - (position.get_ptr(), 1, type(this->m_holder.alloc(), ::boost::forward(args)...)); + return this->priv_forward_range_insert( position.get_ptr(), 1, type(this->m_holder.alloc() + , ::boost::forward(args)...), alloc_version()); } #else @@ -1154,8 +1290,8 @@ class vector void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ T* back_pos = container_detail::to_raw_pointer \ - (this->m_holder.m_start) + this->m_holder.m_size; \ - if (this->m_holder.m_size < this->m_holder.m_capacity){ \ + (this->m_holder.start()) + this->m_holder.m_size; \ + if (this->m_holder.m_size < this->m_holder.capacity()){ \ allocator_traits_type::construct (this->m_holder.alloc() \ , back_pos BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ ++this->m_holder.m_size; \ @@ -1164,7 +1300,7 @@ class vector container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ proxy \ (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - this->priv_forward_range_insert(back_pos, 1, proxy); \ + this->priv_forward_range_insert_at_end(1, proxy, alloc_version()); \ } \ } \ \ @@ -1176,7 +1312,7 @@ class vector proxy \ (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ return this->priv_forward_range_insert \ - (container_detail::to_raw_pointer(pos.get_ptr()), 1, proxy); \ + (container_detail::to_raw_pointer(pos.get_ptr()), 1, proxy, alloc_version()); \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) @@ -1241,7 +1377,7 @@ class vector iterator insert(const_iterator p, size_type n, const T& x) { container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); - return this->priv_forward_range_insert(p.get_ptr(), n, proxy); + return this->priv_forward_range_insert(p.get_ptr(), n, proxy, alloc_version()); } //! Requires: p must be a valid iterator of *this. @@ -1270,7 +1406,7 @@ class vector it = this->emplace(it, *first); ++it; } - return iterator(this->m_holder.m_start + n_pos); + return iterator(this->m_holder.start() + n_pos); } #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1283,7 +1419,7 @@ class vector ) { container_detail::insert_range_proxy proxy(this->m_holder.alloc(), first); - return this->priv_forward_range_insert(pos.get_ptr(), std::distance(first, last), proxy); + return this->priv_forward_range_insert(pos.get_ptr(), std::distance(first, last), proxy, alloc_version()); } #endif @@ -1296,7 +1432,7 @@ class vector { //Destroy last element --this->m_holder.m_size; - this->m_holder.destroy(container_detail::to_raw_pointer(this->m_holder.m_start) + this->m_holder.m_size); + this->priv_destroy(container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size); } //! Effects: Erases the element at position pos. @@ -1308,9 +1444,9 @@ class vector iterator erase(const_iterator position) { T *const pos = container_detail::to_raw_pointer(position.get_ptr()); - T *const beg = container_detail::to_raw_pointer(this->m_holder.m_start); + T *const beg = container_detail::to_raw_pointer(this->m_holder.start()); //Move elements forward and destroy last - this->m_holder.destroy(::boost::move(pos + 1, beg + this->m_holder.m_size, pos)); + this->priv_destroy(::boost::move(pos + 1, beg + this->m_holder.m_size, pos)); --this->m_holder.m_size; return iterator(position.get_ptr()); } @@ -1324,14 +1460,14 @@ class vector iterator erase(const_iterator first, const_iterator last) { if (first != last){ - T* end_pos = container_detail::to_raw_pointer(this->m_holder.m_start) + this->m_holder.m_size; - T* ptr = container_detail::to_raw_pointer(boost::move + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + T* const ptr = container_detail::to_raw_pointer(boost::move (container_detail::to_raw_pointer(last.get_ptr()) ,end_pos ,container_detail::to_raw_pointer(first.get_ptr()) )); const size_type destroyed = (end_pos - ptr); - this->m_holder.destroy_n(ptr, destroyed); + destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed); this->m_holder.m_size -= destroyed; } return iterator(first.get_ptr()); @@ -1342,22 +1478,39 @@ class vector //! Throws: Nothing. //! //! Complexity: Constant. - void swap(vector& x) BOOST_CONTAINER_NOEXCEPT + void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_same::value)) { - //Just swap internals - this->m_holder.swap_members(x.m_holder); + //Just swap internals in case of !allocator_v0. Otherwise, deep swap + this->m_holder.swap(x.m_holder); //And now the allocator container_detail::bool_ flag; container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), flag); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: If T's move constructor throws. + //! + //! Complexity: Linear + //! + //! Note: non-standard extension. + template + void swap(vector & x) + { + this->m_holder.swap(x.m_holder); + } + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Erases all the elements of the vector. //! //! Throws: Nothing. //! //! Complexity: Linear to the number of elements in the vector. void clear() BOOST_CONTAINER_NOEXCEPT - { this->m_holder.destroy_all(); } + { this->priv_destroy_all(); } /// @cond @@ -1377,21 +1530,128 @@ class vector } private: + + void priv_reserve(size_type, allocator_v0) + { + throw_bad_alloc(); + } + + void priv_reserve(size_type new_cap, allocator_v1) + { + //There is not enough memory, allocate a new buffer + pointer p = this->m_holder.allocate(new_cap); + + //We will reuse insert code, so create a dummy input iterator + container_detail::insert_range_proxy, T*> + proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); + //Backwards (and possibly forward) expansion + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( container_detail::to_raw_pointer(p) + , new_cap + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); + } + + void priv_reserve(size_type new_cap, allocator_v2) + { + //There is not enough memory, allocate a new + //buffer or expand the old one. + bool same_buffer_start; + size_type real_cap = 0; + std::pair ret = + this->m_holder.allocation_command + (allocate_new | expand_fwd | expand_bwd, + new_cap, new_cap, real_cap, this->m_holder.start()); + + //Check for forward expansion + same_buffer_start = ret.second && this->m_holder.start() == ret.first; + if(same_buffer_start){ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->m_holder.capacity(real_cap); + } + + //If there is no forward expansion, move objects + else{ + //We will reuse insert code, so create a dummy input iterator + container_detail::insert_range_proxy, T*> + proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); + //Backwards (and possibly forward) expansion + if(ret.second){ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( container_detail::to_raw_pointer(ret.first) + , real_cap + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); + } + //New buffer + else{ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( container_detail::to_raw_pointer(ret.first) + , real_cap + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); + } + } + } + + template + void priv_first_allocation_fill(Proxy proxy, size_type n) + { + //Copy first new elements in pos + proxy.uninitialized_copy_n_and_update + (container_detail::to_raw_pointer(this->m_holder.start()), n); + this->m_holder.m_size = n; + } + + void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT + { + if(!value_traits::trivial_dctr) + allocator_traits_type::destroy(this->get_stored_allocator(), p); + } + + void priv_destroy_last_n(size_type n) BOOST_CONTAINER_NOEXCEPT + { + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n); + this->m_holder.m_size -= n; + } + + void priv_destroy_all() BOOST_CONTAINER_NOEXCEPT + { + destroy_alloc_n(this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + this->m_holder.m_size = 0; + } + template iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) { return this->priv_forward_range_insert - (p.get_ptr(), 1, container_detail::get_insert_value_proxy(this->m_holder.alloc(), ::boost::forward(x))); + ( p.get_ptr(), 1, container_detail::get_insert_value_proxy(this->m_holder.alloc() + , ::boost::forward(x)), alloc_version()); } template void priv_push_back(BOOST_FWD_REF(U) x) { - if (this->m_holder.m_size < this->m_holder.m_capacity){ + if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct ( this->m_holder.alloc() - , container_detail::to_raw_pointer(this->m_holder.m_start + this->m_holder.m_size) + , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) , ::boost::forward(x) ); ++this->m_holder.m_size; } @@ -1400,42 +1660,40 @@ class vector } } + void priv_shrink_to_fit(allocator_v0) + {} + void priv_shrink_to_fit(allocator_v1) { - if(this->m_holder.m_capacity){ - if(!this->size()){ + const size_type cp = this->m_holder.capacity(); + if(cp){ + const size_type sz = this->size(); + if(!sz){ this->m_holder.deallocate(); } - else{ + else if(sz < cp){ //Allocate a new buffer. - size_type real_cap = 0; - std::pair ret = - this->m_holder.allocation_command - (allocate_new, this->size(), this->size(), real_cap, this->m_holder.m_start); - if(real_cap < this->capacity()){ - //We will reuse insert code, so create a dummy input iterator - container_detail::insert_range_proxy, T*> - proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->m_holder.m_start) - , 0 - , proxy); - } - else{ - this->m_holder.alloc().deallocate(ret.first, real_cap); - } + pointer p = this->m_holder.allocate(sz); + + //We will reuse insert code, so create a dummy input iterator + container_detail::insert_range_proxy, T*> + proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( container_detail::to_raw_pointer(p) + , sz + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); } } } void priv_shrink_to_fit(allocator_v2) { - if(this->m_holder.m_capacity){ + if(this->m_holder.capacity()){ if(!size()){ this->m_holder.deallocate(); } @@ -1444,8 +1702,8 @@ class vector if(this->m_holder.allocation_command ( shrink_in_place | nothrow_allocation , this->capacity(), this->size() - , received_size, this->m_holder.m_start).first){ - this->m_holder.m_capacity = received_size; + , received_size, this->m_holder.start()).first){ + this->m_holder.capacity(received_size); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_shrink; #endif @@ -1456,77 +1714,136 @@ class vector template iterator priv_forward_range_insert - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) { //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.m_capacity - this->m_holder.m_size; - const size_type n_pos = pos - this->m_holder.m_start; + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + const size_type n_pos = pos - this->m_holder.start(); T *const raw_pos = container_detail::to_raw_pointer(pos); - //Check if we already have room - if(alloc_version::value > 1){ //Version 2 allocator, compile time check - bool same_buffer_start = n <= remaining; - if (!same_buffer_start){ - size_type real_cap = 0; - //There is not enough memory, allocate a new - //buffer or expand the old one. - std::pair ret = (this->m_holder.allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.m_start)); + if (n <= remaining){ + this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + } + else{ + //This will trigger an error + throw_bad_alloc(); + } - //Buffer reallocated - if(ret.second){ - //Forward expansion, delay insertion - if(this->m_holder.m_start == ret.first){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->m_holder.m_capacity = real_cap; - //Expand forward - this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); - } - //Backwards (and possibly forward) expansion - else{ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( container_detail::to_raw_pointer(ret.first) - , real_cap, raw_pos, n, insert_range_proxy); - } + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + if (n <= remaining){ + this->priv_range_insert_at_end_expand_forward(n, insert_range_proxy); + } + else{ + //This will trigger an error + throw_bad_alloc(); + } + + return this->end(); + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + + if (n <= remaining){ + this->priv_range_insert_expand_forward + (raw_pos, n, insert_range_proxy); + } + else{ + const size_type new_cap = this->m_holder.next_capacity(n); + T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap)); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( new_buf, new_cap, raw_pos, n, insert_range_proxy); + } + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + return this->priv_forward_range_insert(this->cend().get_ptr(), n, insert_range_proxy, allocator_v1()); + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + + bool same_buffer_start = n <= remaining; + if (!same_buffer_start){ + size_type real_cap = 0; + //There is not enough memory, allocate a new + //buffer or expand the old one. + std::pair ret = (this->m_holder.allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start())); + + //Buffer reallocated + if(ret.second){ + //Forward expansion, delay insertion + if(this->m_holder.start() == ret.first){ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->m_holder.capacity(real_cap); + //Expand forward + this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); } - //New buffer + //Backwards (and possibly forward) expansion else{ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; + ++this->num_expand_bwd; #endif - this->priv_range_insert_new_allocation + this->priv_range_insert_expand_backwards ( container_detail::to_raw_pointer(ret.first) , real_cap, raw_pos, n, insert_range_proxy); } } + //New buffer else{ - //Expand forward - this->priv_range_insert_expand_forward - (raw_pos, n, insert_range_proxy); - } - } - else{ //Version 1 allocator - if (n <= remaining){ - this->priv_range_insert_expand_forward - (raw_pos, n, insert_range_proxy); - } - else{ - const size_type new_cap = this->m_holder.next_capacity(n); - T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap)); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif this->priv_range_insert_new_allocation - ( new_buf, new_cap, raw_pos, n, insert_range_proxy); + ( container_detail::to_raw_pointer(ret.first) + , real_cap, raw_pos, n, insert_range_proxy); } } - return iterator(this->m_holder.m_start + n_pos); + else{ + //Expand forward + this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + } + + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) + { + return this->priv_forward_range_insert(this->cend().get_ptr(), n, insert_range_proxy, allocator_v2()); } //Absolutely experimental. This function might change, disappear or simply crash! @@ -1536,7 +1853,7 @@ class vector { const size_type old_size_pos = this->size(); this->reserve(old_size_pos + element_count); - T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.m_start); + T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); size_type insertions_left = element_count; size_type next_pos = old_size_pos; size_type hole_size = element_count; @@ -1649,7 +1966,7 @@ class vector BOOST_ASSERT(first_pos <= last_pos); BOOST_ASSERT(last_pos <= limit_pos); // - T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.m_start); + T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); T* const first_ptr = begin_ptr + first_pos; T* const last_ptr = begin_ptr + last_pos; @@ -1678,18 +1995,25 @@ class vector } private: + template + void priv_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) + { + T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); + this->m_holder.m_size += n; + } + template void priv_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case if(!n) return; //There is enough memory - T* const old_finish = container_detail::to_raw_pointer(this->m_holder.m_start) + this->m_holder.m_size; + T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; const size_type elems_after = old_finish - pos; if (!elems_after){ - //Copy first new elements in pos - insert_range_proxy.uninitialized_copy_n_and_update(pos, n); + insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); this->m_holder.m_size += n; } else if (elems_after >= n){ @@ -1716,7 +2040,7 @@ class vector this->m_holder.m_size += n; } BOOST_CATCH(...){ - this->m_holder.destroy_n(pos + n, elems_after); + destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); BOOST_RETHROW } BOOST_CATCH_END @@ -1736,10 +2060,10 @@ class vector //Initialize with [begin(), pos) old buffer //the start of the new buffer - T *old_buffer = container_detail::to_raw_pointer(this->m_holder.m_start); + T *old_buffer = container_detail::to_raw_pointer(this->m_holder.start()); if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc - (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.m_start), pos, old_finish = new_finish); + (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.start()), pos, old_finish = new_finish); constructed_values_destroyer.increment_size(new_finish - old_finish); } //Initialize new objects, starting from previous point @@ -1754,12 +2078,12 @@ class vector //Destroy and deallocate old elements //If there is allocated memory, destroy and deallocate if(!value_traits::trivial_dctr_after_move) - this->m_holder.destroy_n(old_buffer, this->m_holder.m_size); - this->m_holder.alloc().deallocate(this->m_holder.m_start, this->m_holder.m_capacity); + destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size); + this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity()); } - this->m_holder.m_start = new_start; - this->m_holder.m_size = new_finish - new_start; - this->m_holder.m_capacity = new_cap; + this->m_holder.start(new_start); + this->m_holder.m_size = new_finish - new_start; + this->m_holder.capacity(new_cap); //All construction successful, disable rollbacks constructed_values_destroyer.release(); scoped_alloc.release(); @@ -1772,7 +2096,7 @@ class vector { //n can be zero to just expand capacity //Backup old data - T* const old_start = container_detail::to_raw_pointer(this->m_holder.m_start); + T* const old_start = container_detail::to_raw_pointer(this->m_holder.start()); T* const old_finish = old_start + this->m_holder.m_size; const size_type old_size = this->m_holder.m_size; @@ -1782,8 +2106,8 @@ class vector const size_type before_plus_new = elemsbefore + n; //Update the vector buffer information to a safe state - this->m_holder.m_start = new_start; - this->m_holder.m_capacity = new_capacity; + this->m_holder.start(new_start); + this->m_holder.capacity(new_capacity); this->m_holder.m_size = 0; //If anything goes wrong, this object will destroy @@ -1850,7 +2174,7 @@ class vector //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; if(!value_traits::trivial_dctr_after_move) - this->m_holder.destroy_n(to_destroy, n_destroy); + destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -1924,7 +2248,7 @@ class vector //they have trivial destructor after being moved const size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - this->m_holder.destroy_n(move_end, n_destroy); + destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -1980,7 +2304,7 @@ class vector //have trivial destructor after being moved size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - this->m_holder.destroy_n(move_end, n_destroy); + destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -2061,7 +2385,7 @@ class vector this->m_holder.m_size += n_after; } BOOST_CATCH(...){ - this->m_holder.destroy_n(pos, mid_last_dist); + destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist); BOOST_RETHROW } BOOST_CATCH_END diff --git a/proj/vc7ide/static_vector_test.vcproj b/proj/vc7ide/static_vector_test.vcproj new file mode 100644 index 0000000..2ada060 --- /dev/null +++ b/proj/vc7ide/static_vector_test.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/movable.hpp b/test/movable.hpp new file mode 100644 index 0000000..3076865 --- /dev/null +++ b/test/movable.hpp @@ -0,0 +1,92 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// 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/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_MOVE_TEST_MOVABLE_HPP +#define BOOST_MOVE_TEST_MOVABLE_HPP + +//[movable_definition +//header file "movable.hpp" +#include + +//A movable class +class movable +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable) + int value_; + +public: + movable() : value_(1){} + + //Move constructor and assignment + movable(BOOST_RV_REF(movable) m) + { value_ = m.value_; m.value_ = 0; } + + movable & operator=(BOOST_RV_REF(movable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + bool moved() const //Observer + { return value_ == 0; } +}; + + +class copy_movable +{ + BOOST_COPYABLE_AND_MOVABLE(copy_movable) + int value_; + +public: + copy_movable(int value = 1) : value_(value){} + + //Move constructor and assignment + copy_movable(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; } + + copy_movable(const copy_movable &m) + { value_ = m.value_; } + + copy_movable & operator=(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m) + { value_ = m.value_; return *this; } + + bool moved() const //Observer + { return value_ == 0; } + + bool operator==(const copy_movable& m) const + { return value_ == m.value_; } +}; + +struct copy_movable_wrapper +{ + copy_movable cm; +}; + +copy_movable produce() +{ return copy_movable(); } + +namespace boost{ + +template<> +struct has_nothrow_move +{ + static const bool value = true; +}; + +template<> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} //namespace boost{ +//] + +#endif //BOOST_MOVE_TEST_MOVABLE_HPP diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp new file mode 100644 index 0000000..f12e7e1 --- /dev/null +++ b/test/static_vector_test.cpp @@ -0,0 +1,803 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to 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) +#include +#include +#include + +namespace boost { +namespace container { +namespace test { + +//lightweight_test.hpp does not offer support to check if an operation throws +//so write our own macro +inline void throw_failed_impl(char const * excep, char const * file, int line, char const * function) +{ + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << file << "(" << line << "): Exception '" << excep << "' not thrown in function '" + << function << "'" << std::endl; + ++boost::detail::test_errors(); +} + +} //namespace detail { +} //namespace container { +} //namespace boost { + +#define BOOST_TEST_THROW( S, E ) \ + try { \ + S; \ + ::boost::container::test::throw_failed_impl \ + (#E, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ + } \ + catch( E const&) { \ + } \ +// + +// TODO: Disable parts of the unit test that should not run when BOOST_NO_EXCEPTIONS +// if exceptions are enabled there must be a user defined throw_exception function +#ifdef BOOST_NO_EXCEPTIONS +namespace boost { + void throw_exception(std::exception const & e){}; // user defined +} // namespace boost +#endif // BOOST_NO_EXCEPTIONS + +#include +#include + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +#include +#include +#endif + +#include "static_vector_test.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::static_vector; + +}} + + +template +void test_ctor_ndc() +{ + static_vector s; + BOOST_TEST_EQ(s.size() , 0u); + BOOST_TEST(s.capacity() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(0u), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS +} + +template +void test_ctor_nc(size_t n) +{ + static_vector s(n); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(n), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + if ( 1 < n ) + { + T val10(10); + s[0] = val10; + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + T val20(20); + s.at(1) = val20; + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_ctor_nd(size_t n, T const& v) +{ + static_vector s(n, v); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(n), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_resize_nc(size_t n) +{ + static_vector s; + + s.resize(n); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(n), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + if ( 1 < n ) + { + T val10(10); + s[0] = val10; + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + T val20(20); + s.at(1) = val20; + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_resize_nd(size_t n, T const& v) +{ + static_vector s; + + s.resize(n, v); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(n), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_push_back_nd() +{ + static_vector s; + + BOOST_TEST(s.size() == 0); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(0), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + BOOST_TEST(s.size() == i + 1); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(i + 1), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + BOOST_TEST(T(i) == s.at(i)); + BOOST_TEST(T(i) == s[i]); + BOOST_TEST(T(i) == s.back()); + BOOST_TEST(T(0) == s.front()); + BOOST_TEST(T(i) == *(s.data() + i)); + } +} + +template +void test_pop_back_nd() +{ + static_vector s; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + } + + for ( size_t i = N ; i > 1 ; --i ) + { + s.pop_back(); + BOOST_TEST(s.size() == i - 1); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW( s.at(i - 1), std::out_of_range ); +#endif // BOOST_NO_EXCEPTIONS + BOOST_TEST(T(i - 2) == s.at(i - 2)); + BOOST_TEST(T(i - 2) == s[i - 2]); + BOOST_TEST(T(i - 2) == s.back()); + BOOST_TEST(T(0) == s.front()); + } +} + +template +void test_compare_ranges(It1 first1, It1 last1, It2 first2, It2 last2) +{ + BOOST_TEST(std::distance(first1, last1) == std::distance(first2, last2)); + for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2 ) + BOOST_TEST(*first1 == *first2); +} + +template +void test_copy_and_assign(C const& c) +{ + { + static_vector s(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } + { + static_vector s; + BOOST_TEST(0 == s.size()); + s.assign(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } +} + +template +void test_copy_and_assign_nd(T const& val) +{ + static_vector s; + std::vector v; + std::list l; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + v.push_back(t); + l.push_back(t); + } + // copy ctor + { + static_vector s1(s); + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + // copy assignment + { + static_vector s1; + BOOST_TEST(0 == s1.size()); + s1 = s; + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + + // ctor(Iter, Iter) and assign(Iter, Iter) + test_copy_and_assign(s); + test_copy_and_assign(v); + test_copy_and_assign(l); + + // assign(N, V) + { + static_vector s1(s); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + std::vector a(N, val); + s1.assign(N, val); + test_compare_ranges(a.begin(), a.end(), s1.begin(), s1.end()); + } + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + stable_vector bsv(s.begin(), s.end()); + vector bv(s.begin(), s.end()); + test_copy_and_assign(bsv); + test_copy_and_assign(bv); +#endif +} + +template +void test_iterators_nd() +{ + static_vector s; + std::vector v; + + for ( size_t i = 0 ; i < N ; ++i ) + { + s.push_back(T(i)); + v.push_back(T(i)); + } + + test_compare_ranges(s.begin(), s.end(), v.begin(), v.end()); + test_compare_ranges(s.rbegin(), s.rend(), v.rbegin(), v.rend()); + + s.assign(v.rbegin(), v.rend()); + + test_compare_ranges(s.begin(), s.end(), v.rbegin(), v.rend()); + test_compare_ranges(s.rbegin(), s.rend(), v.begin(), v.end()); +} + +template +void test_erase_nd() +{ + static_vector s; + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < N ; ++i ) + s.push_back(T(i)); + + // erase(pos) + { + for ( size_t i = 0 ; i < N ; ++i ) + { + static_vector s1(s); + It it = s1.erase(s1.begin() + i); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - 1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+1 ; j < N ; ++j ) + BOOST_TEST(s1[j-1] == T(j)); + } + } + // erase(first, last) + { + size_t n = N/3; + for ( size_t i = 0 ; i <= N ; ++i ) + { + static_vector s1(s); + size_t removed = i + n < N ? n : N - i; + It it = s1.erase(s1.begin() + i, s1.begin() + i + removed); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - removed); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+n ; j < N ; ++j ) + BOOST_TEST(s1[j-n] == T(j)); + } + } +} + +template +void test_insert(SV const& s, C const& c) +{ + size_t h = N/2; + size_t n = size_t(h/1.5f); + + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + + typename C::const_iterator it = c.begin(); + std::advance(it, n); + typename static_vector::iterator + it1 = s1.insert(s1.begin() + i, c.begin(), it); + + BOOST_TEST(s1.begin() + i == it1); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == T(100 + j)); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } +} + +template +void test_insert_nd(T const& val) +{ + size_t h = N/2; + + static_vector s, ss; + std::vector v; + std::list l; + + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < h ; ++i ) + { + s.push_back(T(i)); + ss.push_back(T(100 + i)); + v.push_back(T(100 + i)); + l.push_back(T(100 + i)); + } + + // insert(pos, val) + { + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + BOOST_TEST(s1[i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+1] == T(j+i)); + } + } + // insert(pos, n, val) + { + size_t n = size_t(h/1.5f); + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, n, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } + } + // insert(pos, first, last) + test_insert(s, ss); + test_insert(s, v); + test_insert(s, l); + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + stable_vector bsv(ss.begin(), ss.end()); + vector bv(ss.begin(), ss.end()); + test_insert(s, bv); + test_insert(s, bsv); +#endif +} + +template +void test_capacity_0_nd() +{ + static_vector v(5u, T(0)); + + static_vector s; + BOOST_TEST(s.size() == 0); + BOOST_TEST(s.capacity() == 0); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW(s.at(0), std::out_of_range); + BOOST_TEST_THROW(s.resize(5u, T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), 5u, T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROW(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROW(s.assign(5u, T(0)), std::bad_alloc); + try{ + static_vector s2(v.begin(), v.end()); + BOOST_TEST(false); + }catch(std::bad_alloc &){} + try{ + static_vector s1(5u, T(0)); + BOOST_TEST(false); + }catch(std::bad_alloc &){} +#endif // BOOST_NO_EXCEPTIONS +} + +template +void test_exceptions_nd() +{ + static_vector v(N, T(0)); + static_vector s(N/2, T(0)); + +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW(s.resize(N, T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), N, T(0)), std::bad_alloc); + BOOST_TEST_THROW(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROW(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROW(s.assign(N, T(0)), std::bad_alloc); + try{ + static_vector s2(v.begin(), v.end()); + BOOST_TEST(false); + }catch(std::bad_alloc &){} + try{ + static_vector s1(N, T(0)); + BOOST_TEST(false); + }catch(std::bad_alloc &){} +#endif // BOOST_NO_EXCEPTIONS +} + +template +void test_swap_and_move_nd() +{ + { + static_vector v1, v2, v3, v4; + static_vector s1, s2; + static_vector s4; + + for (size_t i = 0 ; i < N ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + v4.push_back(T(i)); + } + for (size_t i = 0 ; i < N/2 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + s4.push_back(T(100 + i)); + } + + s1.swap(v1); + s2 = boost::move(v2); + static_vector s3(boost::move(v3)); + s4.swap(v4); + + BOOST_TEST(v1.size() == N/2); + BOOST_TEST(s1.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s3.size() == N); + BOOST_TEST(v4.size() == N/2); + BOOST_TEST(s4.size() == N); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(v1[i] == T(100 + i)); + BOOST_TEST(v4[i] == T(100 + i)); + } + for (size_t i = 0 ; i < N ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + BOOST_TEST(s4[i] == T(i)); + } + } + { + static_vector v1, v2, v3; + static_vector s1, s2; + + for (size_t i = 0 ; i < N/2 ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + } + for (size_t i = 0 ; i < N/3 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + } + + s1.swap(v1); + s2 = boost::move(v2); + static_vector s3(boost::move(v3)); + + BOOST_TEST(v1.size() == N/3); + BOOST_TEST(s1.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s3.size() == N/2); + for (size_t i = 0 ; i < N/3 ; ++i ) + BOOST_TEST(v1[i] == T(100 + i)); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + } + } + { + static_vector v(N, T(0)); + static_vector s(N/2, T(1)); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW(s.swap(v), std::bad_alloc); + v.resize(N, T(0)); + BOOST_TEST_THROW(s = boost::move(v), std::bad_alloc); + v.resize(N, T(0)); + try { + static_vector s2(boost::move(v)); + BOOST_TEST(false); + } catch (std::bad_alloc &) {} +#endif // BOOST_NO_EXCEPTIONS + } +} + +template +void test_emplace_0p() +{ + //emplace_back() + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(); + BOOST_TEST(v.size() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW(v.emplace_back(), std::bad_alloc); +#endif + } +} + +template +void test_emplace_2p() +{ + //emplace_back(pos, int, int) + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(i, 100 + i); + BOOST_TEST(v.size() == N); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_TEST_THROW(v.emplace_back(N, 100 + N), std::bad_alloc); +#endif + BOOST_TEST(v.size() == N); + for (int i = 0 ; i < int(N) ; ++i ) + BOOST_TEST(v[i] == T(i, 100 + i)); + } + + // emplace(pos, int, int) + { + typedef typename static_vector::iterator It; + + int h = N / 2; + + static_vector v; + for ( int i = 0 ; i < h ; ++i ) + v.emplace_back(i, 100 + i); + + for ( int i = 0 ; i <= h ; ++i ) + { + static_vector vv(v); + It it = vv.emplace(vv.begin() + i, i+100, i+200); + BOOST_TEST(vv.begin() + i == it); + BOOST_TEST(vv.size() == size_t(h+1)); + for ( int j = 0 ; j < i ; ++j ) + BOOST_TEST(vv[j] == T(j, j+100)); + BOOST_TEST(vv[i] == T(i+100, i+200)); + for ( int j = 0 ; j < h-i ; ++j ) + BOOST_TEST(vv[j+i+1] == T(j+i, j+i+100)); + } + } +} + +template +void test_sv_elem(T const& t) +{ + typedef static_vector V; + + static_vector v; + + v.push_back(V(N/2, t)); + V vvv(N/2, t); + v.push_back(boost::move(vvv)); + v.insert(v.begin(), V(N/2, t)); + v.insert(v.end(), V(N/2, t)); + v.emplace_back(N/2, t); +} + +int main(int, char* []) +{ + BOOST_TEST(counting_value::count() == 0); + + test_ctor_ndc(); + test_ctor_ndc(); + test_ctor_ndc(); + BOOST_TEST(counting_value::count() == 0); + test_ctor_ndc(); + test_ctor_ndc(); + + test_ctor_nc(5); + test_ctor_nc(5); + test_ctor_nc(5); + BOOST_TEST(counting_value::count() == 0); + test_ctor_nc(5); + test_ctor_nc(5); + + test_ctor_nd(5, 1); + test_ctor_nd(5, value_nd(1)); + test_ctor_nd(5, counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_ctor_nd(5, shptr_value(1)); + test_ctor_nd(5, produce()); + + test_resize_nc(5); + test_resize_nc(5); + test_resize_nc(5); + BOOST_TEST(counting_value::count() == 0); + test_resize_nc(5); + test_resize_nc(5); + + test_resize_nd(5, 1); + test_resize_nd(5, value_nd(1)); + test_resize_nd(5, counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_resize_nd(5, shptr_value(1)); + test_resize_nd(5, produce()); + + test_push_back_nd(); + test_push_back_nd(); + test_push_back_nd(); + BOOST_TEST(counting_value::count() == 0); + test_push_back_nd(); + test_push_back_nd(); + + test_pop_back_nd(); + test_pop_back_nd(); + test_pop_back_nd(); + BOOST_TEST(counting_value::count() == 0); + test_pop_back_nd(); + test_pop_back_nd(); + + test_copy_and_assign_nd(1); + test_copy_and_assign_nd(value_nd(1)); + test_copy_and_assign_nd(counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_copy_and_assign_nd(shptr_value(1)); + test_copy_and_assign_nd(produce()); + + test_iterators_nd(); + test_iterators_nd(); + test_iterators_nd(); + BOOST_TEST(counting_value::count() == 0); + test_iterators_nd(); + test_iterators_nd(); + + test_erase_nd(); + test_erase_nd(); + test_erase_nd(); + BOOST_TEST(counting_value::count() == 0); + test_erase_nd(); + test_erase_nd(); + + test_insert_nd(50); + test_insert_nd(value_nd(50)); + test_insert_nd(counting_value(50)); + BOOST_TEST(counting_value::count() == 0); + test_insert_nd(shptr_value(50)); + test_insert_nd(produce()); + + test_capacity_0_nd(); + test_capacity_0_nd(); + test_capacity_0_nd(); + BOOST_TEST(counting_value::count() == 0); + test_capacity_0_nd(); + test_capacity_0_nd(); + + test_exceptions_nd(); + test_exceptions_nd(); + test_exceptions_nd(); + BOOST_TEST(counting_value::count() == 0); + test_exceptions_nd(); + test_exceptions_nd(); + + test_swap_and_move_nd(); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + BOOST_TEST(counting_value::count() == 0); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + + test_emplace_0p(); + BOOST_TEST(counting_value::count() == 0); + + test_emplace_2p(); + BOOST_TEST(counting_value::count() == 0); + + test_sv_elem(50); + test_sv_elem(value_nd(50)); + test_sv_elem(counting_value(50)); + BOOST_TEST(counting_value::count() == 0); + test_sv_elem(shptr_value(50)); + test_sv_elem(copy_movable(50)); + + return boost::report_errors(); +} + +#include diff --git a/test/static_vector_test.hpp b/test/static_vector_test.hpp new file mode 100644 index 0000000..3dfe697 --- /dev/null +++ b/test/static_vector_test.hpp @@ -0,0 +1,99 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to 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) + +#ifndef BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP +#define BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP + +#include + +#include +#include "movable.hpp" + +using namespace boost::container; + +class value_ndc +{ +public: + explicit value_ndc(int a) : aa(a) {} + ~value_ndc() {} + bool operator==(value_ndc const& v) const { return aa == v.aa; } + bool operator<(value_ndc const& v) const { return aa < v.aa; } +private: + value_ndc(value_ndc const&) {} + value_ndc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class value_nd +{ +public: + explicit value_nd(int a) : aa(a) {} + ~value_nd() {} + bool operator==(value_nd const& v) const { return aa == v.aa; } + bool operator<(value_nd const& v) const { return aa < v.aa; } +private: + int aa; +}; + +class value_nc +{ +public: + explicit value_nc(int a = 0) : aa(a) {} + ~value_nc() {} + bool operator==(value_nc const& v) const { return aa == v.aa; } + bool operator<(value_nc const& v) const { return aa < v.aa; } +private: + value_nc(value_nc const&) {} + value_nc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class counting_value +{ + BOOST_COPYABLE_AND_MOVABLE(counting_value) + +public: + explicit counting_value(int a = 0, int b = 0) : aa(a), bb(b) { ++c(); } + counting_value(counting_value const& v) : aa(v.aa), bb(v.bb) { ++c(); } + counting_value(BOOST_RV_REF(counting_value) p) : aa(p.aa), bb(p.bb) { p.aa = 0; p.bb = 0; ++c(); } // Move constructor + counting_value& operator=(BOOST_RV_REF(counting_value) p) { aa = p.aa; p.aa = 0; bb = p.bb; p.bb = 0; return *this; } // Move assignment + counting_value& operator=(BOOST_COPY_ASSIGN_REF(counting_value) p) { aa = p.aa; bb = p.bb; return *this; } // Copy assignment + ~counting_value() { --c(); } + bool operator==(counting_value const& v) const { return aa == v.aa && bb == v.bb; } + bool operator<(counting_value const& v) const { return aa < v.aa || ( aa == v.aa && bb < v.bb ); } + static size_t count() { return c(); } + +private: + static size_t & c() { static size_t co = 0; return co; } + int aa, bb; +}; + +namespace boost { + +template <> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} + +class shptr_value +{ + typedef boost::shared_ptr Ptr; +public: + explicit shptr_value(int a = 0) : m_ptr(new int(a)) {} + bool operator==(shptr_value const& v) const { return *m_ptr == *(v.m_ptr); } + bool operator<(shptr_value const& v) const { return *m_ptr < *(v.m_ptr); } +private: + boost::shared_ptr m_ptr; +}; + +#endif // BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP