// Boost.Container varray // // Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2011-2013 Andrew Hundt. // Copyright (c) 2014-2014 Ion Gaztanaga // // 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_DETAIL_VARRAY_HPP #define BOOST_CONTAINER_DETAIL_VARRAY_HPP #ifndef BOOST_CONFIG_HPP # include #endif #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include //algo_equal(), algo_lexicographical_compare #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif #include #include #include #include #include //adl_move_swap #include "varray_util.hpp" #include #include #include #ifndef BOOST_NO_EXCEPTIONS #include #endif // BOOST_NO_EXCEPTIONS /** * @defgroup varray_non_member varray non-member functions */ namespace boost { namespace container { namespace dtl { // Forward declaration template class varray; namespace strategy { // TODO: Improve error messages // possibly include N in the strategy, and provide size as an optoinal allocate_failed parameter? // Example of current error with reserve(4) when capacity is 3: // "boost/container/varray.hpp(66): size can't exceed the capacity" // Could say // "cannot reserve(4) due to fixed capacity of 3 elements" //! @brief The default strategy. //! //! @tparam Value Type of element stored in the container. template struct def { typedef Value value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef Value* pointer; typedef const Value* const_pointer; typedef Value& reference; typedef const Value& const_reference; static void allocate_failed() { BOOST_ASSERT_MSG(false, "size can't exceed the capacity"); } }; //! @brief The strategy adapting info from passed Allocator. //! //! This strategy defines the same types that are defined in the Allocator. //! //! @tparam Allocator The Allocator which will be adapted. template struct allocator_adaptor { typedef typename Allocator::value_type value_type; typedef typename Allocator::size_type size_type; typedef typename Allocator::difference_type difference_type; typedef typename Allocator::pointer pointer; typedef typename Allocator::const_pointer const_pointer; typedef typename Allocator::reference reference; typedef typename Allocator::const_reference const_reference; static void allocate_failed() { BOOST_ASSERT_MSG(false, "size can't exceed the capacity"); } }; } // namespace strategy struct varray_error_handler { template static void check_capacity(varray const&, std::size_t s) { if ( Capacity < s ) S::allocate_failed(); } template static void check_at(varray const& v, typename varray::size_type i) { (void)v; (void)i; // TODO - use BOOST_THROW_EXCEPTION here? #ifndef BOOST_NO_EXCEPTIONS if ( v.size() <= i ) throw std::out_of_range("index out of bounds"); #else // BOOST_NO_EXCEPTIONS BOOST_ASSERT_MSG(i < v.size(), "index out of bounds"); #endif // BOOST_NO_EXCEPTIONS } template static void check_operator_brackets(varray const& v, typename varray::size_type i) { (void)v; (void)i; BOOST_ASSERT_MSG(i < v.size(), "index out of bounds"); } template static void check_empty(varray const& v) { (void)v; BOOST_ASSERT_MSG(0 < v.size(), "the container is empty"); } template static void check_iterator_end_neq(varray const& v, typename varray::const_iterator position) { (void)v; (void)position; BOOST_ASSERT_MSG(v.begin() <= position && position < v.end(), "iterator out of bounds"); } template static void check_iterator_end_eq(varray const& v, typename varray::const_iterator position) { (void)v; (void)position; BOOST_ASSERT_MSG(v.begin() <= position && position <= v.end(), "iterator out of bounds"); } }; template struct varray_traits { typedef typename Strategy::value_type value_type; typedef typename Strategy::size_type size_type; typedef typename Strategy::difference_type difference_type; typedef typename Strategy::pointer pointer; typedef typename Strategy::const_pointer const_pointer; typedef typename Strategy::reference reference; typedef typename Strategy::const_reference const_reference; typedef varray_error_handler error_handler; typedef false_type use_memop_in_swap_and_move; typedef false_type use_optimized_swap; typedef false_type disable_trivial_init; }; /** * @brief A variable-size array container with fixed capacity. * * varray 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 varray 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 varray 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 varray unlike C arrays or std::array which must construct * all elements on instantiation. The behavior of varray 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 result in undefined behavior unless * otherwise specified. In this respect if size() == capacity(), then varray::push_back() * behaves like std::vector pop_front() if size() == empty(). The reason for this difference * is because unlike vectors, varray does not perform allocation. * * @par Advanced Usage * Error handling behavior can be modified to more closely match std::vector exception behavior * when exceeding bounds by providing an alternate Strategy and varray_traits instantiation. * * @tparam Value The type of element that will be stored. * @tparam Capacity The maximum number of elements varray can store, fixed at compile time. * @tparam Strategy Defines the public typedefs and error handlers, * implements StaticVectorStrategy and has some similarities * to an Allocator. */ template > class varray { typedef dtl::varray_traits< Value, Capacity, Strategy > vt; typedef typename vt::error_handler errh; typedef typename aligned_storage< sizeof(Value[Capacity]), boost::container::dtl::alignment_of::value >::type aligned_storage_type; template friend class varray; BOOST_COPYABLE_AND_MOVABLE(varray) #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES public: template varray & operator=(varray & sv) { typedef varray other; this->operator=(static_cast &>(const_cast(sv))); return *this; } #endif public: //! @brief The type of elements stored in the container. typedef typename vt::value_type value_type; //! @brief The unsigned integral type used by the container. typedef typename vt::size_type size_type; //! @brief The pointers difference type. typedef typename vt::difference_type difference_type; //! @brief The pointer type. typedef typename vt::pointer pointer; //! @brief The const pointer type. typedef typename vt::const_pointer const_pointer; //! @brief The value reference type. typedef typename vt::reference reference; //! @brief The value const reference type. typedef typename vt::const_reference const_reference; //! @brief The iterator type. typedef pointer iterator; //! @brief The const iterator type. typedef const_pointer const_iterator; //! @brief The reverse iterator type. typedef boost::container::reverse_iterator reverse_iterator; //! @brief The const reverse iterator. typedef boost::container::reverse_iterator const_reverse_iterator; //! @brief The type of a strategy used by the varray. typedef Strategy strategy_type; //! @brief Constructs an empty varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). varray() : m_size(0) {} //! @pre count <= capacity() //! //! @brief Constructs a varray containing count value initialized Values. //! //! @param count The number of values which will be contained in the container. //! //! @par Throws //! If Value's value initialization throws. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). explicit varray(size_type count) : m_size(0) { this->resize(count); // may throw } //! @pre count <= capacity() //! //! @brief Constructs a varray 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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). varray(size_type count, value_type const& value) : m_size(0) { this->resize(count, value); // may throw } //! @pre //! @li distance(first, last) <= capacity() //! @li Iterator must meet the \c ForwardIterator. //! //! @brief Constructs a varray 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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template varray(Iterator first, Iterator last) : m_size(0) { this->assign(first, last); // may throw } //! @brief Constructs a copy of other varray. //! //! @param other The varray which content will be copied to this one. //! //! @par Throws //! If Value's copy constructor throws. //! //! @par Complexity //! Linear O(N). varray(varray const& other) : m_size(other.size()) { namespace sv = varray_detail; sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw } //! @pre other.size() <= capacity(). //! //! @brief Constructs a copy of other varray. //! //! @param other The varray which content will be copied to this one. //! //! @par Throws //! If Value's copy constructor throws. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template varray(varray const& other) : m_size(other.size()) { errh::check_capacity(*this, other.size()); // may throw namespace sv = varray_detail; sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw } //! @brief Copy assigns Values stored in the other varray to this one. //! //! @param other The varray which content will be copied to this one. //! //! @par Throws //! If Value's copy constructor or copy assignment throws. //! //! @par Complexity //! Linear O(N). varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other) { this->assign(other.begin(), other.end()); // may throw return *this; } //! @pre other.size() <= capacity() //! //! @brief Copy assigns Values stored in the other varray to this one. //! //! @param other The varray which content will be copied to this one. //! //! @par Throws //! If Value's copy constructor or copy assignment throws. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template // TEMPORARY WORKAROUND #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) varray & operator=(::boost::rv< varray > const& other) #else varray & operator=(varray const& other) #endif { this->assign(other.begin(), other.end()); // may throw return *this; } //! @brief Move constructor. Moves Values stored in the other varray to this one. //! //! @param other The varray 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. //! @internal //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. //! @endinternal //! //! @par Complexity //! Linear O(N). varray(BOOST_RV_REF(varray) other) { typedef typename vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); } //! @pre other.size() <= capacity() //! //! @brief Move constructor. Moves Values stored in the other varray to this one. //! //! @param other The varray 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. //! @internal //! @li It throws only if \c use_memop_in_swap_and_move is false_type - default. //! @endinternal //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template varray(BOOST_RV_REF_3_TEMPL_ARGS(varray, value_type, C, S) other) : m_size(other.m_size) { errh::check_capacity(*this, other.size()); // may throw typedef typename vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); } //! @brief Move assignment. Moves Values stored in the other varray to this one. //! //! @param other The varray 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. //! @internal //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. //! @endinternal //! //! @par Complexity //! Linear O(N). varray & operator=(BOOST_RV_REF(varray) other) { if ( &other == this ) return *this; typedef typename vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; this->move_assign_dispatch(other, use_memop_in_swap_and_move()); return *this; } //! @pre other.size() <= capacity() //! //! @brief Move assignment. Moves Values stored in the other varray to this one. //! //! @param other The varray 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. //! @internal //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. //! @endinternal //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template varray & operator=(BOOST_RV_REF_3_TEMPL_ARGS(varray, value_type, C, S) other) { errh::check_capacity(*this, other.size()); // may throw typedef typename vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; this->move_assign_dispatch(other, use_memop_in_swap_and_move()); return *this; } //! @brief Destructor. Destroys Values stored in this container. //! //! @par Throws //! Nothing //! //! @par Complexity //! Linear O(N). ~varray() { namespace sv = varray_detail; sv::destroy(this->begin(), this->end()); } //! @brief Swaps contents of the other varray and this one. //! //! @param other The varray 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, //! @internal //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. //! @endinternal //! //! @par Complexity //! Linear O(N). void swap(varray & other) { typedef typename vt::use_optimized_swap use_optimized_swap; this->swap_dispatch(other, use_optimized_swap()); } //! @pre other.size() <= capacity() && size() <= other.capacity() //! //! @brief Swaps contents of the other varray and this one. //! //! @param other The varray 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, //! @internal //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. //! @endinternal //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template void swap(varray & other) { errh::check_capacity(*this, other.size()); errh::check_capacity(other, this->size()); typedef typename vt::use_optimized_swap use_optimized_swap; this->swap_dispatch(other, use_optimized_swap()); } //! @pre count <= capacity() //! //! @brief Inserts or erases elements at the end such that //! the size becomes count. New elements are value initialized. //! //! @param count The number of elements which will be stored in the container. //! //! @par Throws //! If Value's value initialization throws. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). void resize(size_type count) { namespace sv = varray_detail; typedef typename vt::disable_trivial_init dti; if ( count < m_size ) { sv::destroy(this->begin() + count, this->end()); } else { errh::check_capacity(*this, count); // may throw sv::uninitialized_fill(this->end(), this->begin() + count, dti()); // may throw } m_size = count; // update end } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). void resize(size_type count, value_type const& value) { if ( count < m_size ) { namespace sv = varray_detail; sv::destroy(this->begin() + count, this->end()); } else { errh::check_capacity(*this, count); // may throw std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw } m_size = count; // update end } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). void reserve(size_type count) { errh::check_capacity(*this, count); // may throw } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant O(1). void push_back(value_type const& value) { typedef typename vt::disable_trivial_init dti; errh::check_capacity(*this, m_size + 1); // may throw namespace sv = varray_detail; sv::construct(dti(), this->end(), value); // may throw ++m_size; // update end } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant O(1). void push_back(BOOST_RV_REF(value_type) value) { typedef typename vt::disable_trivial_init dti; errh::check_capacity(*this, m_size + 1); // may throw namespace sv = varray_detail; sv::construct(dti(), this->end(), ::boost::move(value)); // may throw ++m_size; // update end } //! @pre !empty() //! //! @brief Destroys last value and decreases the size. //! //! @par Throws //! Nothing by default. //! //! @par Complexity //! Constant O(1). void pop_back() { errh::check_empty(*this); namespace sv = varray_detail; sv::destroy(this->end() - 1); --m_size; // update end } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant or linear. iterator insert(iterator position, value_type const& value) { return this->priv_insert(position, 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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant or linear. iterator insert(iterator position, BOOST_RV_REF(value_type) value) { return this->priv_insert(position, boost::move(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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). iterator insert(iterator position, size_type count, value_type const& value) { errh::check_iterator_end_eq(*this, position); errh::check_capacity(*this, m_size + count); // may throw if ( position == this->end() ) { std::uninitialized_fill(position, position + count, value); // may throw m_size += count; // update end } else { namespace sv = varray_detail; difference_type to_move = boost::container::iterator_distance(position, this->end()); // TODO - should following lines check for exception and revert to the old size? if ( count < static_cast(to_move) ) { sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw m_size += count; // update end sv::move_backward(position, position + to_move - count, this->end() - count); // may throw std::fill_n(position, count, value); // may throw } else { std::uninitialized_fill(this->end(), position + count, value); // may throw m_size += count - to_move; // update end sv::uninitialized_move(position, position + to_move, position + count); // may throw m_size += to_move; // update end std::fill_n(position, to_move, value); // may throw } } return position; } //! @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 ForwardIterator. //! //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Linear O(N). template iterator insert(iterator position, Iterator first, Iterator last) { this->insert_dispatch(position, first, last); return position; } //! @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) { namespace sv = varray_detail; errh::check_iterator_end_neq(*this, position); //TODO - add empty check? //errh::check_empty(*this); sv::move(position + 1, this->end(), position); // may throw sv::destroy(this->end() - 1); --m_size; return 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) { namespace sv = varray_detail; errh::check_iterator_end_eq(*this, first); errh::check_iterator_end_eq(*this, last); difference_type n = boost::container::iterator_distance(first, last); //TODO - add invalid range check? //BOOST_ASSERT_MSG(0 <= n, "invalid range"); //TODO - add this->size() check? //BOOST_ASSERT_MSG(n <= this->size(), "invalid range"); sv::move(last, this->end(), first); // may throw sv::destroy(this->end() - n, this->end()); m_size -= n; return first; } //! @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) { this->assign_dispatch(first, last); // may throw } //! @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) { if ( count < m_size ) { namespace sv = varray_detail; std::fill_n(this->begin(), count, value); // may throw sv::destroy(this->begin() + count, this->end()); } else { errh::check_capacity(*this, count); // may throw std::fill_n(this->begin(), m_size, value); // may throw std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw } m_size = count; // update end } #if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant O(1). template void emplace_back(BOOST_FWD_REF(Args) ...args) { typedef typename vt::disable_trivial_init dti; errh::check_capacity(*this, m_size + 1); // may throw namespace sv = varray_detail; sv::construct(dti(), this->end(), ::boost::forward(args)...); // may throw ++m_size; // update end } //! @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. //! @internal //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). //! @endinternal //! //! @par Complexity //! Constant or linear. template iterator emplace(iterator position, BOOST_FWD_REF(Args) ...args) { typedef typename vt::disable_trivial_init dti; namespace sv = varray_detail; errh::check_iterator_end_eq(*this, position); errh::check_capacity(*this, m_size + 1); // may throw if ( position == this->end() ) { sv::construct(dti(), position, ::boost::forward(args)...); // may throw ++m_size; // update end } else { // TODO - should following lines check for exception and revert to the old size? // TODO - should move be used only if it's nonthrowing? value_type & r = *(this->end() - 1); sv::construct(dti(), this->end(), boost::move(r)); // may throw ++m_size; // update end sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw typename aligned_storage ::value>::type temp_storage; value_type * val_p = static_cast(static_cast(&temp_storage)); sv::construct(dti(), val_p, ::boost::forward(args)...); // may throw sv::scoped_destructor d(val_p); sv::assign(position, ::boost::move(*val_p)); // may throw } return position; } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || BOOST_CONTAINER_DOXYGEN_INVOKED #define BOOST_CONTAINER_VARRAY_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ void emplace_back(BOOST_MOVE_UREF##N)\ {\ typedef typename vt::disable_trivial_init dti;\ errh::check_capacity(*this, m_size + 1);/*may throw*/\ \ namespace sv = varray_detail;\ sv::construct(dti(), this->end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ ++m_size; /*update end*/\ }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace(iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ typedef typename vt::disable_trivial_init dti;\ namespace sv = varray_detail;\ errh::check_iterator_end_eq(*this, position);\ errh::check_capacity(*this, m_size + 1); /*may throw*/\ if ( position == this->end() ){\ sv::construct(dti(), position BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ ++m_size; /*update end*/\ }\ else{\ /* TODO - should following lines check for exception and revert to the old size? */\ /* TODO - should move be used only if it's nonthrowing? */\ value_type & r = *(this->end() - 1);\ sv::construct(dti(), this->end(), boost::move(r));/*may throw*/\ ++m_size; /*update end*/\ sv::move_backward(position, this->end() - 2, this->end() - 1);/*may throw*/\ typename aligned_storage\ ::value>::type temp_storage;\ value_type * val_p = static_cast(static_cast(&temp_storage));\ sv::construct(dti(), val_p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ sv::scoped_destructor d(val_p);\ sv::assign(position, ::boost::move(*val_p));/*may throw*/\ }\ return position;\ }\ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VARRAY_EMPLACE_CODE) #undef BOOST_CONTAINER_VARRAY_EMPLACE_CODE #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || BOOST_CONTAINER_DOXYGEN_INVOKED #endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE //! @brief Removes all elements from the container. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). void clear() { namespace sv = varray_detail; sv::destroy(this->begin(), this->end()); m_size = 0; // update end } //! @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) { errh::check_at(*this, i); // may throw return *(this->begin() + 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 { errh::check_at(*this, i); // may throw return *(this->begin() + i); } //! @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) { // TODO: Remove bounds check? std::vector and std::array operator[] don't check. errh::check_operator_brackets(*this, i); return *(this->begin() + 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 { errh::check_operator_brackets(*this, i); return *(this->begin() + i); } //! @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() { errh::check_empty(*this); return *(this->begin()); } //! @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 { errh::check_empty(*this); return *(this->begin()); } //! @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() { errh::check_empty(*this); return *(this->end() - 1); } //! @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 { errh::check_empty(*this); return *(this->end() - 1); } //! @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() { return (addressof)(*(this->ptr())); } //! @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 { return (addressof)(*(this->ptr())); } //! @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() { return this->ptr(); } //! @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 { return this->ptr(); } //! @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 { return this->ptr(); } //! @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() { return this->begin() + m_size; } //! @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 { return this->begin() + m_size; } //! @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 { return this->cbegin() + m_size; } //! @brief Returns reverse iterator to the first element of the reversed container. //! //! @return reverse_iterator pointing to the beginning //! of the reversed varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). reverse_iterator rbegin() { return reverse_iterator(this->end()); } //! @brief Returns const reverse iterator to the first element of the reversed container. //! //! @return const_reverse_iterator pointing to the beginning //! of the reversed varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } //! @brief Returns const reverse iterator to the first element of the reversed container. //! //! @return const_reverse_iterator pointing to the beginning //! of the reversed varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } //! @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 varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). reverse_iterator rend() { return reverse_iterator(this->begin()); } //! @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 varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } //! @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 varray. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } //! @brief Returns container's capacity. //! //! @return container's capacity. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). static size_type capacity() { return Capacity; } //! @brief Returns container's capacity. //! //! @return container's capacity. //! //! @par Throws //! Nothing. //! //! @par Complexity //! Constant O(1). static size_type max_size() { return Capacity; } //! @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 { return m_size; } //! @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 { return 0 == m_size; } private: // @par Throws // Nothing. // @par Complexity // Linear O(N). template void move_ctor_dispatch(varray & other, true_type /*use_memop*/) { ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); m_size = other.m_size; } // @par Throws // @li If boost::has_nothrow_move::value is true and Value's move constructor throws // @li If boost::has_nothrow_move::value is false and Value's copy constructor throws. // @par Complexity // Linear O(N). template void move_ctor_dispatch(varray & other, false_type /*use_memop*/) { namespace sv = varray_detail; sv::uninitialized_move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw m_size = other.m_size; } // @par Throws // Nothing. // @par Complexity // Linear O(N). template void move_assign_dispatch(varray & other, true_type /*use_memop*/) { this->clear(); ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); boost::adl_move_swap(m_size, other.m_size); } // @par Throws // @li If boost::has_nothrow_move::value is true and Value's move constructor or move assignment throws // @li If boost::has_nothrow_move::value is false and Value's copy constructor or move assignment throws. // @par Complexity // Linear O(N). template void move_assign_dispatch(varray & other, false_type /*use_memop*/) { namespace sv = varray_detail; if ( m_size <= static_cast(other.size()) ) { sv::move_if_noexcept(other.begin(), other.begin() + m_size, this->begin()); // may throw // TODO - perform uninitialized_copy first? sv::uninitialized_move_if_noexcept(other.begin() + m_size, other.end(), this->end()); // may throw } else { sv::move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw sv::destroy(this->begin() + other.size(), this->end()); } m_size = other.size(); // update end } // @par Throws // Nothing. // @par Complexity // Linear O(N). template void swap_dispatch(varray & other, true_type const& /*use_optimized_swap*/) { typedef typename if_c< Capacity < C, aligned_storage_type, typename varray::aligned_storage_type >::type storage_type; storage_type temp_storage; value_type * temp_ptr = static_cast(static_cast(&temp_storage)); ::memcpy(temp_ptr, this->data(), sizeof(Value) * this->size()); ::memcpy(this->data(), other.data(), sizeof(Value) * other.size()); ::memcpy(other.data(), temp_ptr, sizeof(Value) * this->size()); boost::adl_move_swap(m_size, other.m_size); } // @par Throws // If Value's move constructor or move assignment throws // but only if use_memop_in_swap_and_move is false_type - default. // @par Complexity // Linear O(N). template void swap_dispatch(varray & other, false_type const& /*use_optimized_swap*/) { namespace sv = varray_detail; typedef typename vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; if ( this->size() < other.size() ) swap_dispatch_impl(this->begin(), this->end(), other.begin(), other.end(), use_memop_in_swap_and_move()); // may throw else swap_dispatch_impl(other.begin(), other.end(), this->begin(), this->end(), use_memop_in_swap_and_move()); // may throw boost::adl_move_swap(m_size, other.m_size); } // @par Throws // Nothing. // @par Complexity // Linear O(N). void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, true_type const& /*use_memop*/) { //BOOST_ASSERT_MSG(boost::container::iterator_distance(first_sm, last_sm) <= boost::container::iterator_distance(first_la, last_la)); namespace sv = varray_detail; for (; first_sm != last_sm ; ++first_sm, ++first_la) { typename aligned_storage< sizeof(value_type), alignment_of::value >::type temp_storage; value_type * temp_ptr = static_cast(static_cast(&temp_storage)); ::memcpy(temp_ptr, (addressof)(*first_sm), sizeof(value_type)); ::memcpy((addressof)(*first_sm), (addressof)(*first_la), sizeof(value_type)); ::memcpy((addressof)(*first_la), temp_ptr, sizeof(value_type)); } ::memcpy(first_sm, first_la, sizeof(value_type) * boost::container::iterator_distance(first_la, last_la)); } // @par Throws // If Value's move constructor or move assignment throws. // @par Complexity // Linear O(N). void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, false_type const& /*use_memop*/) { //BOOST_ASSERT_MSG(boost::container::iterator_distance(first_sm, last_sm) <= boost::container::iterator_distance(first_la, last_la)); namespace sv = varray_detail; for (; first_sm != last_sm ; ++first_sm, ++first_la) { //boost::adl_move_swap(*first_sm, *first_la); // may throw value_type temp(boost::move(*first_sm)); // may throw *first_sm = boost::move(*first_la); // may throw *first_la = boost::move(temp); // may throw } sv::uninitialized_move(first_la, last_la, first_sm); // may throw sv::destroy(first_la, last_la); } // insert // @par Throws // If Value's move constructor or move assignment throws // or if Value's copy assignment throws. // @par Complexity // Linear O(N). template iterator priv_insert(iterator position, V & value) { typedef typename vt::disable_trivial_init dti; namespace sv = varray_detail; errh::check_iterator_end_eq(*this, position); errh::check_capacity(*this, m_size + 1); // may throw if ( position == this->end() ) { sv::construct(dti(), position, value); // may throw ++m_size; // update end } else { // TODO - should following lines check for exception and revert to the old size? // TODO - should move be used only if it's nonthrowing? value_type & r = *(this->end() - 1); sv::construct(dti(), this->end(), boost::move(r)); // may throw ++m_size; // update end sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw sv::assign(position, value); // may throw } return position; } // insert // @par Throws // If Value's move constructor, move assignment throws // or if Value's copy constructor or copy assignment throws. // @par Complexity // Linear O(N). template typename iterator_enable_if_tag::type insert_dispatch(iterator position, Iterator first, Iterator last) { errh::check_iterator_end_eq(*this, position); size_type count = boost::container::iterator_distance(first, last); errh::check_capacity(*this, m_size + count); // may throw if ( position == this->end() ) { namespace sv = varray_detail; sv::uninitialized_copy(first, last, position); // may throw m_size += count; // update end } else { this->insert_in_the_middle(position, first, last, count); // may throw } } // @par Throws // If Value's move constructor, move assignment throws // or if Value's copy constructor or copy assignment throws. // @par Complexity // Linear O(N). template typename iterator_disable_if_tag::type insert_dispatch(iterator position, Iterator first, Iterator last) { errh::check_iterator_end_eq(*this, position); if ( position == this->end() ) { namespace sv = varray_detail; std::ptrdiff_t d = boost::container::iterator_distance(position, this->begin() + Capacity); std::size_t count = sv::uninitialized_copy_s(first, last, position, d); // may throw errh::check_capacity(*this, count <= static_cast(d) ? m_size + count : Capacity + 1); // may throw m_size += count; } else { size_type count = boost::container::iterator_distance(first, last); errh::check_capacity(*this, m_size + count); // may throw this->insert_in_the_middle(position, first, last, count); // may throw } } // @par Throws // If Value's move constructor, move assignment throws // or if Value's copy constructor or copy assignment throws. // @par Complexity // Linear O(N). template void insert_in_the_middle(iterator position, Iterator first, Iterator last, difference_type count) { namespace sv = varray_detail; difference_type to_move = boost::container::iterator_distance(position, this->end()); // TODO - should following lines check for exception and revert to the old size? if ( count < to_move ) { sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw m_size += count; // update end sv::move_backward(position, position + to_move - count, this->end() - count); // may throw sv::copy(first, last, position); // may throw } else { Iterator middle_iter = first; boost::container::iterator_advance(middle_iter, to_move); sv::uninitialized_copy(middle_iter, last, this->end()); // may throw m_size += count - to_move; // update end sv::uninitialized_move(position, position + to_move, position + count); // may throw m_size += to_move; // update end sv::copy(first, middle_iter, position); // may throw } } // assign // @par Throws // If Value's constructor or assignment taking dereferenced Iterator throws. // @par Complexity // Linear O(N). template typename iterator_enable_if_tag::type assign_dispatch(Iterator first, Iterator last) { namespace sv = varray_detail; size_type s = boost::container::iterator_distance(first, last); errh::check_capacity(*this, s); // may throw if ( m_size <= static_cast(s) ) { sv::copy(first, first + m_size, this->begin()); // may throw // TODO - perform uninitialized_copy first? sv::uninitialized_copy(first + m_size, last, this->end()); // may throw } else { sv::copy(first, last, this->begin()); // may throw sv::destroy(this->begin() + s, this->end()); } m_size = s; // update end } // @par Throws // If Value's constructor or assignment taking dereferenced Iterator throws. // @par Complexity // Linear O(N). template typename iterator_disable_if_tag::type assign_dispatch(Iterator first, Iterator last) { namespace sv = varray_detail; size_type s = 0; iterator it = this->begin(); for ( ; it != this->end() && first != last ; ++it, ++first, ++s ) *it = *first; // may throw sv::destroy(it, this->end()); std::ptrdiff_t d = boost::container::iterator_distance(it, this->begin() + Capacity); std::size_t count = sv::uninitialized_copy_s(first, last, it, d); // may throw s += count; errh::check_capacity(*this, count <= static_cast(d) ? s : Capacity + 1); // may throw m_size = s; // update end } pointer ptr() { return pointer(static_cast(static_cast(&m_storage))); } const_pointer ptr() const { return pointer(static_cast(static_cast(&m_storage))); } size_type m_size; aligned_storage_type m_storage; }; #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template class varray { typedef varray_traits< Value, 0, Strategy > vt; typedef typename vt::size_type stored_size_type; typedef typename vt::error_handler errh; public: typedef typename vt::value_type value_type; typedef stored_size_type size_type; typedef typename vt::difference_type difference_type; typedef typename vt::pointer pointer; typedef typename vt::const_pointer const_pointer; typedef typename vt::reference reference; typedef typename vt::const_reference const_reference; typedef pointer iterator; typedef const_pointer const_iterator; typedef boost::container::reverse_iterator reverse_iterator; typedef boost::container::reverse_iterator const_reverse_iterator; // nothrow varray() {} // strong explicit varray(size_type count) { errh::check_capacity(*this, count); // may throw } // strong varray(size_type count, value_type const&) { errh::check_capacity(*this, count); // may throw } // strong varray(varray const& other) { errh::check_capacity(*this, other.size()); } // strong template varray(varray const& other) { errh::check_capacity(*this, other.size()); // may throw } // strong template varray(Iterator first, Iterator last) { errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw } // basic varray & operator=(varray const& other) { errh::check_capacity(*this, other.size()); return *this; } // basic template varray & operator=(varray const& other) { errh::check_capacity(*this, other.size()); // may throw return *this; } // nothrow ~varray() {} // strong void resize(size_type count) { errh::check_capacity(*this, count); // may throw } // strong void resize(size_type count, value_type const&) { errh::check_capacity(*this, count); // may throw } // nothrow void reserve(size_type count) { errh::check_capacity(*this, count); // may throw } // strong void push_back(value_type const&) { errh::check_capacity(*this, 1); // may throw } // nothrow void pop_back() { errh::check_empty(*this); } // basic void insert(iterator position, value_type const&) { errh::check_iterator_end_eq(*this, position); errh::check_capacity(*this, 1); // may throw } // basic void insert(iterator position, size_type count, value_type const&) { errh::check_iterator_end_eq(*this, position); errh::check_capacity(*this, count); // may throw } // basic template void insert(iterator, Iterator first, Iterator last) { errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw } // basic void erase(iterator position) { errh::check_iterator_end_neq(*this, position); } // basic void erase(iterator first, iterator last) { errh::check_iterator_end_eq(*this, first); errh::check_iterator_end_eq(*this, last); //BOOST_ASSERT_MSG(0 <= n, "invalid range"); } // basic template void assign(Iterator first, Iterator last) { errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw } // basic void assign(size_type count, value_type const&) { errh::check_capacity(*this, count); // may throw } // nothrow void clear() {} // strong reference at(size_type i) { errh::check_at(*this, i); // may throw return *(this->begin() + i); } // strong const_reference at(size_type i) const { errh::check_at(*this, i); // may throw return *(this->begin() + i); } // nothrow reference operator[](size_type i) { errh::check_operator_brackets(*this, i); return *(this->begin() + i); } // nothrow const_reference operator[](size_type i) const { errh::check_operator_brackets(*this, i); return *(this->begin() + i); } // nothrow reference front() { errh::check_empty(*this); return *(this->begin()); } // nothrow const_reference front() const { errh::check_empty(*this); return *(this->begin()); } // nothrow reference back() { errh::check_empty(*this); return *(this->end() - 1); } // nothrow const_reference back() const { errh::check_empty(*this); return *(this->end() - 1); } // nothrow Value * data() { return (addressof)(*(this->ptr())); } const Value * data() const { return (addressof)(*(this->ptr())); } // nothrow iterator begin() { return this->ptr(); } const_iterator begin() const { return this->ptr(); } const_iterator cbegin() const { return this->ptr(); } iterator end() { return this->begin(); } const_iterator end() const { return this->begin(); } const_iterator cend() const { return this->cbegin(); } // nothrow reverse_iterator rbegin() { return reverse_iterator(this->end()); } const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } reverse_iterator rend() { return reverse_iterator(this->begin()); } const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } // nothrow size_type capacity() const { return 0; } size_type max_size() const { return 0; } size_type size() const { return 0; } bool empty() const { return true; } private: pointer ptr() { return pointer(reinterpret_cast(this)); } const_pointer ptr() const { return const_pointer(reinterpret_cast(this)); } }; #endif // !BOOST_CONTAINER_DOXYGEN_INVOKED //! @brief Checks if contents of two varrays are equal. //! //! @ingroup varray_non_member //! //! @param x The first varray. //! @param y The second varray. //! //! @return \c true if containers have the same size and elements in both containers are equal. //! //! @par Complexity //! Linear O(N). template bool operator== (varray const& x, varray const& y) { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } //! @brief Checks if contents of two varrays are not equal. //! //! @ingroup varray_non_member //! //! @param x The first varray. //! @param y The second varray. //! //! @return \c true if containers have different size or elements in both containers are not equal. //! //! @par Complexity //! Linear O(N). template bool operator!= (varray const& x, varray const& y) { return !(x==y); } //! @brief Lexicographically compares varrays. //! //! @ingroup varray_non_member //! //! @param x The first varray. //! @param y The second varray. //! //! @return \c true if x compares lexicographically less than y. //! //! @par Complexity //! Linear O(N). template bool operator< (varray const& x, varray const& y) { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } //! @brief Lexicographically compares varrays. //! //! @ingroup varray_non_member //! //! @param x The first varray. //! @param y The second varray. //! //! @return \c true if y compares lexicographically less than x. //! //! @par Complexity //! Linear O(N). template bool operator> (varray const& x, varray const& y) { return y bool operator<= (varray const& x, varray const& y) { return !(y bool operator>= (varray const& x, varray const& y) { return !(x inline void swap(varray & x, varray & y) { x.swap(y); } }}} // namespace boost::container::dtl #include #endif // BOOST_CONTAINER_DETAIL_VARRAY_HPP