From 0896d04ddff022766a35b029e5e70d58812354f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 Feb 2013 13:13:36 +0000 Subject: [PATCH] Additional vector speed improvements, added basic benchmark against varray [SVN r83126] --- bench/Jamfile.v2 | 34 + bench/bench_static_vector.cpp | 147 ++ bench/detail/varray.hpp | 2274 +++++++++++++++++ bench/detail/varray_concept.hpp | 60 + bench/detail/varray_util.hpp | 712 ++++++ bench/varray.hpp | 994 +++++++ doc/container.qbk | 3 +- include/boost/container/allocator_traits.hpp | 16 +- .../container/detail/advanced_insert_int.hpp | 16 +- include/boost/container/static_vector.hpp | 68 +- include/boost/container/vector.hpp | 539 ++-- proj/vc7ide/container.sln | 16 + proj/vc7ide/container.vcproj | 26 + test/Jamfile.v2 | 2 +- test/movable.hpp | 92 - test/movable_int.hpp | 97 +- test/static_vector_test.cpp | 1115 ++++---- test/static_vector_test.hpp | 2 +- test/vector_test.hpp | 7 +- 19 files changed, 5296 insertions(+), 924 deletions(-) create mode 100644 bench/Jamfile.v2 create mode 100644 bench/bench_static_vector.cpp create mode 100644 bench/detail/varray.hpp create mode 100644 bench/detail/varray_concept.hpp create mode 100644 bench/detail/varray_util.hpp create mode 100644 bench/varray.hpp delete mode 100644 test/movable.hpp diff --git a/bench/Jamfile.v2 b/bench/Jamfile.v2 new file mode 100644 index 0000000..25add18 --- /dev/null +++ b/bench/Jamfile.v2 @@ -0,0 +1,34 @@ +# Boost Container Library Test Jamfile + +# (C) Copyright Ion Gaztanaga 2009. +# Use, modification and distribution are 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) + +# Adapted from John Maddock's TR1 Jamfile.v2 +# Copyright John Maddock 2005. +# Use, modification and distribution are 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) + +# this rule enumerates through all the sources and invokes +# the run rule for each source, the result is a list of all +# the run rules, which we can pass on to the test_suite rule: + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) /boost/timer//boost_timer /boost/system//boost_system /boost/thread//boost_thread + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite container_test : [ test_all r ] ; diff --git a/bench/bench_static_vector.cpp b/bench/bench_static_vector.cpp new file mode 100644 index 0000000..bbcaed1 --- /dev/null +++ b/bench/bench_static_vector.cpp @@ -0,0 +1,147 @@ +// benchmark based on: http://cpp-next.com/archive/2010/10/howards-stl-move-semantics-benchmark/ +// +// @file bench_static_vector.cpp +// @date Aug 14, 2011 +// @author Andrew Hundt +// +// (C) 2011-2012 Andrew Hundt +// (C) 2013 Ion Gaztanaga +// +// 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) +// +// @brief varray_benchmark.cpp compares the performance of boost::container::varray to boost::container::vector + +#include "varray.hpp" +#include "boost/container/vector.hpp" +#include "boost/container/static_vector.hpp" +#include "../test/movable_int.hpp" +#include +#include +#include +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +#ifdef NDEBUG +static const std::size_t N = 1000; +#else +static const std::size_t N = 100; +#endif + +#define BENCH_SIMPLE_CONSTRUCTION +//#define BENCH_TRIVIAL_TYPE + +#ifdef BENCH_TRIVIAL_TYPE +typedef std::size_t basic_type_t; +#else +typedef boost::container::test::copyable_int basic_type_t; +#endif + +template +T &get_set(std::size_t) +{ + #ifdef BENCH_SIMPLE_CONSTRUCTION + T &t = *new T(N); + for (std::size_t i = 0; i < N; ++i) + t[i] = basic_type_t(std::rand()); + #else + T &t = *new T; + t.reserve(N); + for (std::size_t i = 0; i < N; ++i) + t.push_back(basic_type_t(std::rand())); + #endif + return t; +} + +template +T &generate() +{ + T &v = *new T; + v.reserve(N); + + for (std::size_t i = 0; i < N; ++i){ + typename T::reference r = get_set(i); + v.push_back(boost::move(r)); + delete &r; + } + return v; +} + +template +cpu_times time_it() +{ + cpu_timer sortTime,rotateTime,destructionTime; + sortTime.stop();rotateTime.stop();destructionTime.stop(); + cpu_timer totalTime, constructTime; + std::srand (0); + for(std::size_t i = 0; i< N; ++i){ + + constructTime.resume(); + { + T &v = generate(); + constructTime.stop(); + sortTime.resume(); + std::sort(v.begin(), v.end()); + sortTime.stop(); + rotateTime.resume(); + std::rotate(v.begin(), v.begin() + v.size()/2, v.end()); + rotateTime.stop(); + + destructionTime.resume(); + delete &v; + } + destructionTime.stop(); + } + totalTime.stop(); + std::cout << " construction took " << boost::timer::format(constructTime.elapsed()); + std::cout << " sort took " << boost::timer::format(sortTime.elapsed()); + std::cout << " rotate took " << boost::timer::format(rotateTime.elapsed()); + std::cout << " destruction took " << boost::timer::format(destructionTime.elapsed()); + std::cout << " Total time = " << boost::timer::format(totalTime.elapsed()) << std::endl; + return totalTime.elapsed(); +} + +void compare_times(cpu_times time_numerator, cpu_times time_denominator){ + std::cout + << "\n wall = " << ((double)time_numerator.wall/(double)time_denominator.wall) + << "\n user = " << ((double)time_numerator.user/(double)time_denominator.user) + << "\n system = " << ((double)time_numerator.system/(double)time_denominator.system) + << "\n (user+system) = " << ((double)(time_numerator.system+time_numerator.user)/(double)(time_denominator.system+time_denominator.user)) << "\n\n"; +} + +int main() +{ + try { + std::cout << "N = " << N << "\n\n"; + + std::cout << "varray benchmark:\n"; + cpu_times time_varray = time_it,N > >(); + + std::cout << "boost::container::static_vector benchmark\n"; + cpu_times time_boost_static_vector = time_it,N > >(); + + std::cout << "boost::container::vector benchmark\n"; + cpu_times time_boost_vector = time_it > >(); + + std::cout << "std::vector benchmark\n"; + cpu_times time_standard_vector = time_it > >(); + + std::cout << "varray/boost::container::vector total time comparison:"; + compare_times(time_varray, time_boost_vector); + + std::cout << "varray/boost::container::static_vector total time comparison:"; + compare_times(time_varray, time_boost_static_vector); + + std::cout << "varray/std::vector total time comparison:"; + compare_times(time_varray,time_standard_vector); + }catch(std::exception e){ + std::cout << e.what(); + } + return 1; +} diff --git a/bench/detail/varray.hpp b/bench/detail/varray.hpp new file mode 100644 index 0000000..e28eb47 --- /dev/null +++ b/bench/detail/varray.hpp @@ -0,0 +1,2274 @@ +// Boost.Container varray +// +// 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_DETAIL_VARRAY_HPP +#define BOOST_CONTAINER_DETAIL_VARRAY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +#include "varray_util.hpp" +#include "varray_concept.hpp" +#include + +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif // BOOST_NO_EXCEPTIONS + +#include +#include +#include +#include + +#include + +#include +#include +#include + +// TODO - use std::reverse_iterator and std::iterator_traits +// instead Boost.Iterator to remove dependency? +// or boost/detail/iterator.hpp ? +#include + +/** + * @defgroup varray_non_member varray non-member functions + */ + +namespace boost { namespace container { namespace container_detail { + +// 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 boost::false_type use_memop_in_swap_and_move; + typedef boost::false_type use_optimized_swap; + typedef boost::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 container_detail::varray_traits< + Value, Capacity, Strategy + > vt; + + typedef typename vt::error_handler errh; + + BOOST_MPL_ASSERT_MSG( + ( boost::is_unsigned::value && + sizeof(typename boost::uint_value_t::least) <= sizeof(typename vt::size_type) ), + SIZE_TYPE_IS_TOO_SMALL_FOR_SPECIFIED_CAPACITY, + (varray) + ); + + BOOST_CONCEPT_ASSERT((concept::VArrayStrategy)); + + typedef boost::aligned_storage< + sizeof(Value[Capacity]), + boost::alignment_of::value + > aligned_storage_type; + + template + friend class varray; + + BOOST_COPYABLE_AND_MOVABLE(varray) + +#ifdef BOOST_NO_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::reverse_iterator reverse_iterator; + //! @brief The const reverse iterator. + typedef boost::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 default constructed Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's default 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). + 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 ForwardTraversalIterator concept. + //! + //! @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) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal)); // Make sure you passed a ForwardIterator + + 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_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 default constructed. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's default 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) + { + 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 = std::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 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. + //! @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) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal)); // Make sure you passed a ForwardIterator + + typedef typename boost::iterator_traversal::type traversal; + this->insert_dispatch(position, first, last, traversal()); + + 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 = std::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) + { + BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal)); // Make sure you passed a ForwardIterator + + typedef typename boost::iterator_traversal::type traversal; + this->assign_dispatch(first, last, traversal()); // 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_CONTAINER_PERFECT_FORWARDING) || 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 + + aligned_storage::value> temp_storage; + value_type * val_p = static_cast(temp_storage.address()); + 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 // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + 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_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + ++m_size; /*update end*/ \ + } \ + // + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace(iterator position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + 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_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*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*/\ + \ + aligned_storage::value> temp_storage; \ + value_type * val_p = static_cast(temp_storage.address()); \ + sv::construct(dti(), val_p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\ + sv::scoped_destructor d(val_p); \ + sv::assign(position, ::boost::move(*val_p)); /*may throw*/\ + } \ + \ + return position; \ + } \ + // + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + +#endif // BOOST_CONTAINER_PERFECT_FORWARDING || 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 boost::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 boost::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, boost::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, boost::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, boost::true_type /*use_memop*/) + { + this->clear(); + + ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); + boost::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, boost::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, boost::true_type const& /*use_optimized_swap*/) + { + typedef typename + boost::mpl::if_c< + Capacity < C, + aligned_storage_type, + typename varray::aligned_storage_type + >::type + storage_type; + + storage_type temp; + Value * temp_ptr = reinterpret_cast(temp.address()); + + ::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::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, boost::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::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, boost::true_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + boost::aligned_storage< + sizeof(value_type), + boost::alignment_of::value + > temp_storage; + value_type * temp_ptr = reinterpret_cast(temp_storage.address()); + + ::memcpy(temp_ptr, boost::addressof(*first_sm), sizeof(value_type)); + ::memcpy(boost::addressof(*first_sm), boost::addressof(*first_la), sizeof(value_type)); + ::memcpy(boost::addressof(*first_la), temp_ptr, sizeof(value_type)); + } + + ::memcpy(first_sm, first_la, sizeof(value_type) * std::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, boost::false_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + //boost::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 + void insert_dispatch(iterator position, Iterator first, Iterator last, boost::random_access_traversal_tag const&) + { + BOOST_CONCEPT_ASSERT((boost_concepts::RandomAccessTraversal)); // Make sure you passed a RandomAccessIterator + + errh::check_iterator_end_eq(*this, position); + + typename boost::iterator_difference::type + count = std::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 + void insert_dispatch(iterator position, Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + errh::check_iterator_end_eq(*this, position); + + if ( position == this->end() ) + { + namespace sv = varray_detail; + + std::ptrdiff_t d = std::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 + { + typename boost::iterator_difference::type + count = std::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 = std::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; + std::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 + void assign_dispatch(Iterator first, Iterator last, boost::random_access_traversal_tag const& /*not_random_access*/) + { + namespace sv = varray_detail; + + typename boost::iterator_difference::type + s = std::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 + void assign_dispatch(Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + 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 = std::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(m_storage.address())); + } + + const_pointer ptr() const + { + return const_pointer(static_cast(m_storage.address())); + } + + 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::reverse_iterator reverse_iterator; + typedef boost::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, count); + } + + // 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, std::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) + { + // TODO - add MPL_ASSERT, check if Iterator is really an iterator + typedef typename boost::iterator_traversal::type traversal; + errh::check_capacity(*this, std::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) + { + // TODO - add MPL_ASSERT, check if Iterator is really an iterator + typedef typename boost::iterator_traversal::type traversal; + errh::check_capacity(*this, std::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 boost::addressof(*(this->ptr())); } + const Value * data() const { return boost::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() && std::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 std::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::container_detail + +#include + +#endif // BOOST_CONTAINER_DETAIL_VARRAY_HPP diff --git a/bench/detail/varray_concept.hpp b/bench/detail/varray_concept.hpp new file mode 100644 index 0000000..ba31aae --- /dev/null +++ b/bench/detail/varray_concept.hpp @@ -0,0 +1,60 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2013 Andrew Hundt. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// +// 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_VARRAY_CONCEPT_HPP +#define BOOST_CONTAINER_VARRAY_CONCEPT_HPP + +#include + +namespace boost { namespace container { namespace container_detail { namespace concept { + +/** + * VArrayStrategyConcept + * + * \brief Checks strategy for varray, which has similarities to std::Allocator + * \ingroup varray + */ +template +struct VArrayStrategy { +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // typedefs are the same as in std::Allocator + 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; + + struct check_methods + { + static void apply() + { + Strategy const* str = 0; + + // must implement allocate_failed + str->allocate_failed(); + + boost::ignore_unused_variable_warning(str); + } + }; + +public : + BOOST_CONCEPT_USAGE(VArrayStrategy) + { + check_methods::apply(); + } + +#endif +}; + +}}}} // namespace boost::container::container_detail::concept + +#endif //BOOST_CONTAINER_VARRAY_CONCEPT_HPP diff --git a/bench/detail/varray_util.hpp b/bench/detail/varray_util.hpp new file mode 100644 index 0000000..23f0d24 --- /dev/null +++ b/bench/detail/varray_util.hpp @@ -0,0 +1,712 @@ +// Boost.Container +// +// varray details +// +// 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_DETAIL_VARRAY_UTIL_HPP +#define BOOST_CONTAINER_DETAIL_VARRAY_UTIL_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include + +#include +#include +#include +#include +#include + +// TODO - move vectors iterators optimization to the other, optional file instead of checking defines? + +#if defined(BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) +#include +#include +#endif // BOOST_CONTAINER_VARRAY_ENABLE_ITERATORS_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +namespace boost { namespace container { namespace varray_detail { + +template +struct are_elements_contiguous : boost::is_pointer +{}; + +#if defined(BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) + +template +struct are_elements_contiguous< + boost::container::container_detail::vector_const_iterator +> : boost::true_type +{}; + +template +struct are_elements_contiguous< + boost::container::container_detail::vector_iterator +> : boost::true_type +{}; + +#if defined(BOOST_DINKUMWARE_STDLIB) + +template +struct are_elements_contiguous< + std::_Vector_const_iterator +> : boost::true_type +{}; + +template +struct are_elements_contiguous< + std::_Vector_iterator +> : boost::true_type +{}; + +#elif defined(BOOST_GNU_STDLIB) + +template +struct are_elements_contiguous< + __gnu_cxx::__normal_iterator > +> : boost::true_type +{}; + +#elif defined(_LIBCPP_VERSION) + +// TODO - test it first +//template +//struct are_elements_contiguous< +// __wrap_iter

+//> : boost::true_type +//{}; + +#else // OTHER_STDLIB + +// TODO - add other iterators implementations + +#endif // STDLIB + +#endif // BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +}}} // namespace boost::container::varray_detail + +namespace boost { namespace container { namespace varray_detail { + +template +struct are_corresponding : + ::boost::mpl::and_< + ::boost::is_same< + ::boost::remove_const< + typename ::boost::iterator_value::type + >, + ::boost::remove_const< + typename ::boost::iterator_value::type + > + >, + are_elements_contiguous, + are_elements_contiguous + > +{}; + +template +struct is_corresponding_value : + ::boost::is_same< + ::boost::remove_const< + typename ::boost::iterator_value::type + >, + ::boost::remove_const + > +{}; + +// destroy(I, I) + +template +void destroy_dispatch(I /*first*/, I /*last*/, + boost::true_type const& /*has_trivial_destructor*/) +{} + +template +void destroy_dispatch(I first, I last, + boost::false_type const& /*has_trivial_destructor*/) +{ + typedef typename boost::iterator_value::type value_type; + for ( ; first != last ; ++first ) + first->~value_type(); +} + +template +void destroy(I first, I last) +{ + typedef typename boost::iterator_value::type value_type; + destroy_dispatch(first, last, has_trivial_destructor()); +} + +// destroy(I) + +template +void destroy_dispatch(I /*pos*/, + boost::true_type const& /*has_trivial_destructor*/) +{} + +template +void destroy_dispatch(I pos, + boost::false_type const& /*has_trivial_destructor*/) +{ + typedef typename boost::iterator_value::type value_type; + pos->~value_type(); +} + +template +void destroy(I pos) +{ + typedef typename boost::iterator_value::type value_type; + destroy_dispatch(pos, has_trivial_destructor()); +} + +// copy(I, I, O) + +template +inline O copy_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + typedef typename boost::iterator_value::type value_type; + typename boost::iterator_difference::type d = std::distance(first, last); + + ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline O copy_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + return std::copy(first, last, dst); // may throw +} + +template +inline O copy(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding, + ::boost::has_trivial_assign< + typename ::boost::iterator_value::type + > + >::type + use_memmove; + + return copy_dispatch(first, last, dst, use_memmove()); // may throw +} + +// uninitialized_copy(I, I, O) + +template +inline +O uninitialized_copy_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value::type value_type; + typename boost::iterator_difference::type d = std::distance(first, last); + + ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline +F uninitialized_copy_dispatch(I first, I last, F dst, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + return std::uninitialized_copy(first, last, dst); // may throw +} + +template +inline +F uninitialized_copy(I first, I last, F dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding, + ::boost::has_trivial_copy< + typename ::boost::iterator_value::type + > + >::type + use_memcpy; + + return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// uninitialized_move(I, I, O) + +template +inline +O uninitialized_move_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value::type value_type; + typename boost::iterator_difference::type d = std::distance(first, last); + + ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline +O uninitialized_move_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + //return boost::uninitialized_move(first, last, dst); // may throw + + O o = dst; + + BOOST_TRY + { + typedef typename std::iterator_traits::value_type value_type; + for (; first != last; ++first, ++o ) + new (boost::addressof(*o)) value_type(boost::move(*first)); + } + BOOST_CATCH(...) + { + destroy(dst, o); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return dst; +} + +template +inline +O uninitialized_move(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding, + ::boost::has_trivial_copy< + typename ::boost::iterator_value::type + > + >::type + use_memcpy; + + return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// TODO - move uses memmove - implement 2nd version using memcpy? + +// move(I, I, O) + +template +inline +O move_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + typedef typename boost::iterator_value::type value_type; + typename boost::iterator_difference::type d = std::distance(first, last); + + ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline +O move_dispatch(I first, I last, O dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + return boost::move(first, last, dst); // may throw +} + +template +inline +O move(I first, I last, O dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding, + ::boost::has_trivial_assign< + typename ::boost::iterator_value::type + > + >::type + use_memmove; + + return move_dispatch(first, last, dst, use_memmove()); // may throw +} + +// move_backward(BDI, BDI, BDO) + +template +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + typedef typename boost::iterator_value::type value_type; + typename boost::iterator_difference::type d = std::distance(first, last); + + BDO foo(dst - d); + ::memmove(boost::addressof(*foo), boost::addressof(*first), sizeof(value_type) * d); + return foo; +} + +template +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + boost::mpl::bool_ const& /*use_memmove*/) +{ + return boost::move_backward(first, last, dst); // may throw +} + +template +inline +BDO move_backward(BDI first, BDI last, BDO dst) +{ + typedef typename + ::boost::mpl::and_< + are_corresponding, + ::boost::has_trivial_assign< + typename ::boost::iterator_value::type + > + >::type + use_memmove; + + return move_backward_dispatch(first, last, dst, use_memmove()); // may throw +} + +template +struct has_nothrow_move : public + ::boost::mpl::or_< + boost::mpl::bool_< + ::boost::has_nothrow_move< + typename ::boost::remove_const::type + >::value + >, + boost::mpl::bool_< + ::boost::has_nothrow_move::value + > + > +{}; + +// uninitialized_move_if_noexcept(I, I, O) + +template +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_ const& /*use_move*/) +{ return uninitialized_move(first, last, dst); } + +template +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_ const& /*use_move*/) +{ return uninitialized_copy(first, last, dst); } + +template +inline +O uninitialized_move_if_noexcept(I first, I last, O dst) +{ + typedef typename has_nothrow_move< + typename ::boost::iterator_value::type + >::type use_move; + + return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// move_if_noexcept(I, I, O) + +template +inline +O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_ const& /*use_move*/) +{ return move(first, last, dst); } + +template +inline +O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_ const& /*use_move*/) +{ return copy(first, last, dst); } + +template +inline +O move_if_noexcept(I first, I last, O dst) +{ + typedef typename has_nothrow_move< + typename ::boost::iterator_value::type + >::type use_move; + + return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// uninitialized_fill(I, I) + +template +inline +void uninitialized_fill_dispatch(I first, I last, + boost::true_type const& /*has_trivial_constructor*/, + boost::true_type const& /*disable_trivial_init*/) +{} + +template +inline +void uninitialized_fill_dispatch(I first, I last, + boost::true_type const& /*has_trivial_constructor*/, + boost::false_type const& /*disable_trivial_init*/) +{ + typedef typename boost::iterator_value::type value_type; + for ( ; first != last ; ++first ) + new (boost::addressof(*first)) value_type(); +} + +template +inline +void uninitialized_fill_dispatch(I first, I last, + boost::false_type const& /*has_trivial_constructor*/, + DisableTrivialInit const& /*not_used*/) +{ + typedef typename boost::iterator_value::type value_type; + I it = first; + + BOOST_TRY + { + for ( ; it != last ; ++it ) + new (boost::addressof(*it)) value_type(); // may throw + } + BOOST_CATCH(...) + { + destroy(first, it); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +template +inline +void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init) +{ + typedef typename boost::iterator_value::type value_type; + uninitialized_fill_dispatch(first, last, boost::has_trivial_constructor(), disable_trivial_init); // may throw +} + +// construct(I) + +template +inline +void construct_dispatch(boost::mpl::bool_ const& /*dont_init*/, I pos) +{} + +template +inline +void construct_dispatch(boost::mpl::bool_ const& /*dont_init*/, I pos) +{ + typedef typename ::boost::iterator_value::type value_type; + new (static_cast(::boost::addressof(*pos))) value_type(); // may throw +} + +template +inline +void construct(DisableTrivialInit const&, I pos) +{ + typedef typename ::boost::iterator_value::type value_type; + typedef typename ::boost::mpl::and_< + boost::has_trivial_constructor, + DisableTrivialInit + >::type dont_init; + + construct_dispatch(dont_init(), pos); // may throw +} + +// construct(I, V) + +template +inline +void construct_dispatch(I pos, V const& v, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template +inline +void construct_dispatch(I pos, P const& p, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + typedef typename boost::iterator_value::type V; + new (static_cast(boost::addressof(*pos))) V(p); // may throw +} + +template +inline +void construct(DisableTrivialInit const&, + I pos, P const& p) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value, + ::boost::has_trivial_copy

+ >::type + use_memcpy; + + construct_dispatch(pos, p, use_memcpy()); // may throw +} + +// Needed by push_back(V &&) + +template +inline +void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value, + ::boost::has_trivial_copy

+ >::type + use_memcpy; + + typedef typename boost::iterator_value::type V; + new (static_cast(boost::addressof(*pos))) V(::boost::move(p)); // may throw +} + +// Needed by emplace_back() and emplace() + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if !defined(BOOST_NO_VARIADIC_TEMPLATES) + +template +inline +void construct(DisableTrivialInit const&, + I pos, + BOOST_FWD_REF(Args) ...args) +{ + typedef typename boost::iterator_value::type V; + new (static_cast(boost::addressof(*pos))) V(::boost::forward(args)...); // may throw +} + +#else // !BOOST_NO_VARIADIC_TEMPLATES + +// BOOST_NO_RVALUE_REFERENCES -> P0 const& p0 +// !BOOST_NO_RVALUE_REFERENCES -> P0 && p0 +// which means that version with one parameter may take V const& v + +#define BOOST_PP_LOCAL_MACRO(n) \ +template \ +inline \ +void construct(DisableTrivialInit const&, \ + I pos, \ + BOOST_CONTAINER_PP_PARAM(P, p) \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ +{ \ + typedef typename boost::iterator_value::type V; \ + new \ + (static_cast(boost::addressof(*pos))) \ + V(p, BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); /*may throw*/ \ +} \ +// +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif // !BOOST_NO_VARIADIC_TEMPLATES +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + +// assign(I, V) + +template +inline +void assign_dispatch(I pos, V const& v, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V)); +} + +template +inline +void assign_dispatch(I pos, V const& v, + boost::mpl::bool_ const& /*use_memcpy*/) +{ + *pos = v; // may throw +} + +template +inline +void assign(I pos, V const& v) +{ + typedef typename + ::boost::mpl::and_< + is_corresponding_value, + ::boost::has_trivial_assign + >::type + use_memcpy; + + assign_dispatch(pos, v, use_memcpy()); // may throw +} + +template +inline +void assign(I pos, BOOST_RV_REF(V) v) +{ + *pos = boost::move(v); // may throw +} + + +// uninitialized_copy_s + +template +inline std::size_t uninitialized_copy_s(I first, I last, F dest, std::size_t max_count) +{ + std::size_t count = 0; + F it = dest; + + BOOST_TRY + { + for ( ; first != last ; ++it, ++first, ++count ) + { + if ( max_count <= count ) + return (std::numeric_limits::max)(); + + // dummy 0 as DisableTrivialInit + construct(0, it, *first); // may throw + } + } + BOOST_CATCH(...) + { + destroy(dest, it); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return count; +} + +// scoped_destructor + +template +class scoped_destructor +{ +public: + scoped_destructor(T * ptr) : m_ptr(ptr) {} + + ~scoped_destructor() + { + if(m_ptr) + destroy(m_ptr); + } + + void release() { m_ptr = 0; } + +private: + T * m_ptr; +}; + +}}} // namespace boost::container::varray_detail + +#endif // BOOST_CONTAINER_DETAIL_VARRAY_UTIL_HPP diff --git a/bench/varray.hpp b/bench/varray.hpp new file mode 100644 index 0000000..8e911cb --- /dev/null +++ b/bench/varray.hpp @@ -0,0 +1,994 @@ +// Boost.Container varray +// +// 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_VARRAY_HPP +#define BOOST_CONTAINER_VARRAY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#include "detail/varray.hpp" + +namespace boost { namespace container { + +/** + * @defgroup varray_non_member varray non-member functions + */ + +/** + * @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. + * The reason for this is because unlike vectors, varray does not perform allocation. + * + * @tparam Value The type of element that will be stored. + * @tparam Capacity The maximum number of elements varray can store, fixed at compile time. + */ +template +class varray + : public container_detail::varray +{ + typedef container_detail::varray base_t; + + BOOST_COPYABLE_AND_MOVABLE(varray) + +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 varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + varray() + : base_t() + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a varray 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 varray(size_type count) + : base_t(count) + {} + + //! @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. + //! + //! @par Complexity + //! Linear O(N). + varray(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 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. + //! + //! @par Complexity + //! Linear O(N). + template + varray(Iterator first, Iterator last) + : base_t(first, last) + {} + + //! @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) + : base_t(other) + {} + + //! @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. + //! + //! @par Complexity + //! Linear O(N). + template + varray(varray const& other) : base_t(other) {} + + //! @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) + { + base_t::operator=(static_cast(other)); + 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. + //! + //! @par Complexity + //! Linear O(N). + template +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_RVALUE_REFERENCES) + varray & operator=(::boost::rv< varray > const& other) +#else + varray & operator=(varray const& other) +#endif + { + base_t::operator=(static_cast const&>(other)); + 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. + //! + //! @par Complexity + //! Linear O(N). + varray(BOOST_RV_REF(varray) other) + : base_t(boost::move(static_cast(other))) + {} + + //! @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. + //! + //! @par Complexity + //! Linear O(N). + template + varray(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + : base_t(boost::move(static_cast&>(other))) + {} + + //! @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. + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_RV_REF(varray) other) + { + base_t::operator=(boost::move(static_cast(other))); + 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. + //! + //! @par Complexity + //! Linear O(N). + template + varray & operator=(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + { + base_t::operator=(boost::move(static_cast&>(other))); + return *this; + } + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~varray(); + + //! @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, + //! + //! @par Complexity + //! Linear O(N). + void swap(varray & other); + + //! @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, + //! + //! @par Complexity + //! Linear O(N). + template + void swap(varray & 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 varray. + //! + //! @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 varray. + //! + //! @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 varray. + //! + //! @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 varray. + //! + //! @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 varray. + //! + //! @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 varray. + //! + //! @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 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); + +//! @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); + +//! @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); + +//! @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); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y don't compare lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator<= (varray const& x, varray const& y); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x don't compare lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator>= (varray const& x, varray const& y); + +//! @brief Swaps contents of two varrays. +//! +//! This function calls varray::swap(). +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @par Complexity +//! Linear O(N). +template +inline void swap(varray & x, varray & y); + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_VARRAY_HPP diff --git a/doc/container.qbk b/doc/container.qbk index 55483bb..152ae74 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -663,7 +663,8 @@ use [*Boost.Container]? There are several reasons for that: * Support for `BOOST_NO_EXCEPTIONS` [@https://svn.boost.org/trac/boost/ticket/7227 #7227]. * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7921 #7921], - [@https://svn.boost.org/trac/boost/ticket/7969 #7969]. + [@https://svn.boost.org/trac/boost/ticket/7969 #7969], + [@https://svn.boost.org/trac/boost/ticket/8118 #8118]. [endsect] diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 828d664..3e9ce0f 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -250,7 +250,19 @@ struct allocator_traits //! Returns: `a.select_on_container_copy_construction()` if that expression is well-formed; //! otherwise, a. - static Alloc select_on_container_copy_construction(const Alloc &a) + static + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + typename container_detail::if_c + < boost::container::container_detail:: + has_member_function_callable_with_select_on_container_copy_construction + ::value + , Alloc + , const Alloc & + >::type + #else + Alloc + #endif + select_on_container_copy_construction(const Alloc &a) { const bool value = boost::container::container_detail:: has_member_function_callable_with_select_on_container_copy_construction @@ -295,7 +307,7 @@ struct allocator_traits static Alloc priv_select_on_container_copy_construction(boost::true_type, const Alloc &a) { return a.select_on_container_copy_construction(); } - static Alloc priv_select_on_container_copy_construction(boost::false_type, const Alloc &a) + static const Alloc &priv_select_on_container_copy_construction(boost::false_type, const Alloc &a) { return a; } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 0b09fdd..2abf805 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -89,10 +89,10 @@ struct insert_n_copies_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { boost::container::uninitialized_fill_alloc_n(this->a_, v_, n, p); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { std::fill_n(p, n, v_); } A &a_; @@ -111,10 +111,10 @@ struct insert_default_constructed_n_proxy : a_(a) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { boost::container::uninitialized_default_alloc_n(this->a_, n, p); } - void copy_n_and_update(Iterator, size_type) + void copy_n_and_update(Iterator, size_type) const { BOOST_ASSERT(false); } @@ -134,7 +134,7 @@ struct insert_copy_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( this->a_ @@ -143,7 +143,7 @@ struct insert_copy_proxy ); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p =v_; @@ -165,7 +165,7 @@ struct insert_move_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( this->a_ @@ -174,7 +174,7 @@ struct insert_move_proxy ); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p = ::boost::move(v_); diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 428c7de..020a208 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -57,20 +57,29 @@ class static_storage_allocator public: typedef T value_type; - T* internal_storage() const + static_storage_allocator() BOOST_CONTAINER_NOEXCEPT + {} + + static_storage_allocator(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + {} + + static_storage_allocator & operator=(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + {} + + T* internal_storage() const BOOST_CONTAINER_NOEXCEPT { return const_cast(static_cast(static_cast(&storage))); } - T* internal_storage() + T* internal_storage() BOOST_CONTAINER_NOEXCEPT { 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 &) + friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT { return false; } - friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) + friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT { return true; } private: @@ -123,7 +132,7 @@ public: //! //! @par Complexity //! Constant O(1). - static_vector() + static_vector() BOOST_CONTAINER_NOEXCEPT : base_t() {} @@ -386,7 +395,7 @@ public: //! //! @par Complexity //! Linear O(N). - void reserve(size_type count); + void reserve(size_type count) BOOST_CONTAINER_NOEXCEPT; //! @pre size() < capacity() //! @@ -594,7 +603,7 @@ public: //! //! @par Complexity //! Constant O(1). - void clear(); + void clear() BOOST_CONTAINER_NOEXCEPT; //! @pre i < size() //! @@ -724,7 +733,7 @@ public: //! //! @par Complexity //! Constant O(1). - Value * data(); + Value * data() BOOST_CONTAINER_NOEXCEPT; //! @brief Const pointer such that [data(), data() + size()) is a valid range. //! For a non-empty vector data() == &front(). @@ -734,7 +743,7 @@ public: //! //! @par Complexity //! Constant O(1). - const Value * data() const; + const Value * data() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns iterator to the first element. //! @@ -745,7 +754,7 @@ public: //! //! @par Complexity //! Constant O(1). - iterator begin(); + iterator begin() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const iterator to the first element. //! @@ -756,7 +765,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_iterator begin() const; + const_iterator begin() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const iterator to the first element. //! @@ -767,7 +776,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_iterator cbegin() const; + const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns iterator to the one after the last element. //! @@ -778,7 +787,7 @@ public: //! //! @par Complexity //! Constant O(1). - iterator end(); + iterator end() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const iterator to the one after the last element. //! @@ -789,7 +798,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_iterator end() const; + const_iterator end() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const iterator to the one after the last element. //! @@ -800,7 +809,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_iterator cend() const; + const_iterator cend() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns reverse iterator to the first element of the reversed container. //! @@ -812,7 +821,7 @@ public: //! //! @par Complexity //! Constant O(1). - reverse_iterator rbegin(); + reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const reverse iterator to the first element of the reversed container. //! @@ -824,7 +833,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_reverse_iterator rbegin() const; + const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const reverse iterator to the first element of the reversed container. //! @@ -836,7 +845,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_reverse_iterator crbegin() const; + const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns reverse iterator to the one after the last element of the reversed container. //! @@ -848,7 +857,7 @@ public: //! //! @par Complexity //! Constant O(1). - reverse_iterator rend(); + reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const reverse iterator to the one after the last element of the reversed container. //! @@ -860,7 +869,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_reverse_iterator rend() const; + const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns const reverse iterator to the one after the last element of the reversed container. //! @@ -872,7 +881,7 @@ public: //! //! @par Complexity //! Constant O(1). - const_reverse_iterator crend() const; + const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT; //! @brief Returns container's capacity. //! @@ -883,7 +892,7 @@ public: //! //! @par Complexity //! Constant O(1). - static size_type capacity(); + static size_type capacity() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns container's capacity. //! @@ -894,7 +903,7 @@ public: //! //! @par Complexity //! Constant O(1). - static size_type max_size(); + static size_type max_size() BOOST_CONTAINER_NOEXCEPT; //! @brief Returns the number of stored elements. //! @@ -905,7 +914,7 @@ public: //! //! @par Complexity //! Constant O(1). - size_type size() const; + size_type size() const BOOST_CONTAINER_NOEXCEPT; //! @brief Queries if the container contains elements. //! @@ -917,7 +926,13 @@ public: //! //! @par Complexity //! Constant O(1). - bool empty() const; + bool empty() const BOOST_CONTAINER_NOEXCEPT; +#else + + friend void swap(static_vector &x, static_vector &y) + { + x.swap(y); + } #endif // BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1026,7 +1041,8 @@ inline void swap(static_vector & x, static_vector & y); #else template -inline void swap(static_vector & x, static_vector & y) +inline void swap(static_vector & x, static_vector & y + , typename container_detail::enable_if_c< C1 != C2>::type * = 0) { x.swap(y); } diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 859445c..3137cec 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -89,7 +89,11 @@ class vector_const_iterator //Constructors vector_const_iterator() BOOST_CONTAINER_NOEXCEPT + #ifndef NDEBUG : m_ptr() + #else + // No value initialization of m_ptr() to speed up things a bit: + #endif {} //Pointer like operators @@ -107,13 +111,13 @@ class vector_const_iterator { ++m_ptr; return *this; } vector_const_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT - { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } + { return vector_const_iterator(m_ptr++); } vector_const_iterator& operator--() BOOST_CONTAINER_NOEXCEPT { --m_ptr; return *this; } vector_const_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT - { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } + { return vector_const_iterator(m_ptr--); } //Arithmetic vector_const_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT @@ -125,11 +129,11 @@ class vector_const_iterator friend vector_const_iterator operator+(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT { return vector_const_iterator(x.m_ptr+off); } - friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT - { return vector_const_iterator(off + right.m_ptr); } + friend vector_const_iterator operator+(difference_type off, vector_const_iterator right) BOOST_CONTAINER_NOEXCEPT + { right.m_ptr += off; return right; } - friend vector_const_iterator operator-(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT - { return vector_const_iterator(x.m_ptr-off); } + friend vector_const_iterator operator-(vector_const_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr += off; return left; } friend difference_type operator-(const vector_const_iterator &left, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT { return left.m_ptr - right.m_ptr; } @@ -159,9 +163,10 @@ template class vector_iterator : public vector_const_iterator { + typedef vector_const_iterator base_t; public: explicit vector_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT - : vector_const_iterator(ptr) + : base_t(ptr) {} public: @@ -173,6 +178,7 @@ class vector_iterator //Constructors vector_iterator() BOOST_CONTAINER_NOEXCEPT + : base_t() {} //Pointer like operators @@ -180,7 +186,7 @@ class vector_iterator { return *this->m_ptr; } value_type* operator->() const BOOST_CONTAINER_NOEXCEPT - { return container_detail::to_raw_pointer(this->m_ptr); } + { return container_detail::to_raw_pointer(this->m_ptr); } reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT { return this->m_ptr[off]; } @@ -190,13 +196,13 @@ class vector_iterator { ++this->m_ptr; return *this; } vector_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT - { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } + { return vector_iterator(this->m_ptr++); } vector_iterator& operator--() BOOST_CONTAINER_NOEXCEPT { --this->m_ptr; return *this; } vector_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT - { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } + { return vector_iterator(this->m_ptr--); } // Arithmetic vector_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT @@ -205,14 +211,14 @@ class vector_iterator vector_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT { this->m_ptr -= off; return *this; } - friend vector_iterator operator+(const vector_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT - { return vector_iterator(x.m_ptr+off); } + friend vector_iterator operator+(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr += off; return left; } - friend vector_iterator operator+(difference_type off, const vector_iterator& right) BOOST_CONTAINER_NOEXCEPT - { return vector_iterator(off + right.m_ptr); } + friend vector_iterator operator+(difference_type off, vector_iterator right) BOOST_CONTAINER_NOEXCEPT + { right.m_ptr += off; return right; } - friend vector_iterator operator-(const vector_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT - { return vector_iterator(x.m_ptr-off); } + friend vector_iterator operator-(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr -= off; return left; } }; template @@ -271,35 +277,38 @@ struct vector_alloc_holder //Constructor, does not throw vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) - : Allocator(), m_start(), m_size(0), m_capacity(0) + : Allocator(), m_start(), m_size(), m_capacity() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT - : Allocator(boost::forward(a)), m_start(), m_size(0), m_capacity(0) + : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() {} //Constructor, does not throw template - explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) - : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) + : Allocator(boost::forward(a)) + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - m_start = this->allocation_command - (allocate_new, cap, cap, m_capacity, m_start).first; + m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first; } //Constructor, does not throw - explicit vector_alloc_holder(size_type cap) - : Allocator(), m_start(), m_size(), m_capacity() + explicit vector_alloc_holder(size_type initial_size) + : Allocator() + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { m_start = this->allocation_command - (allocate_new, cap, cap, m_capacity, m_start).first; + (allocate_new, initial_size, initial_size, m_capacity, m_start).first; } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT : Allocator(boost::move(static_cast(holder))) - , m_start(holder.m_start), m_size(holder.m_size), m_capacity(holder.m_capacity) + , m_start(holder.m_start) + , m_size(holder.m_size) + , m_capacity(holder.m_capacity) { holder.m_start = pointer(); holder.m_size = holder.m_capacity = 0; @@ -311,6 +320,9 @@ struct vector_alloc_holder (allocate_new, cap, cap, m_capacity, m_start).first; } + void first_allocation_same_allocator_type(size_type cap) + { this->first_allocation(cap); } + //Destructor ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT { @@ -347,6 +359,9 @@ struct vector_alloc_holder container_detail::do_swap(this->m_start, x.m_start); container_detail::do_swap(this->m_size, x.m_size); container_detail::do_swap(this->m_capacity, x.m_capacity); + //And now the allocator + container_detail::bool_ flag; + container_detail::swap_alloc(this->alloc(), x.alloc(), flag); } void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT @@ -400,43 +415,50 @@ struct vector_alloc_holder::value) - : Allocator(), m_size(0) + : Allocator(), m_size() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT - : Allocator(boost::forward(a)), m_size(0) + : Allocator(boost::forward(a)), m_size() {} //Constructor, does not throw template - explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) - : Allocator(boost::forward(a)), m_size() + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) + : Allocator(boost::forward(a)) + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - this->first_allocation(cap); + this->first_allocation(initial_size); } //Constructor, does not throw - explicit vector_alloc_holder(size_type cap) - : Allocator(), m_size() + explicit vector_alloc_holder(size_type initial_size) + : Allocator() + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - this->first_allocation(cap); + this->first_allocation(initial_size); } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) : Allocator(boost::move(static_cast(holder))) - , m_size() + , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - this->priv_move_construct_impl(holder); + ::boost::container::uninitialized_move_alloc_n + (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, this->start()); } template vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder BOOST_RV_REF_END holder) : Allocator() - , m_size() + , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort { - this->priv_move_construct_impl(holder); + //Different allocator type so we must check we have enough storage + const size_type n = holder.m_size; + this->first_allocation(n); + ::boost::container::uninitialized_move_alloc_n + (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, this->start()); } void first_allocation(size_type cap) @@ -446,6 +468,9 @@ struct vector_alloc_holder void swap(vector_alloc_holder &x) { - if(this->m_size > x.capacity() || x.m_size > this->capacity()){ + if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){ throw_bad_alloc(); } this->priv_swap_members_impl(x); @@ -484,19 +509,6 @@ struct vector_alloc_holder - 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) { @@ -530,7 +542,10 @@ template #endif class vector { - container_detail::vector_alloc_holder m_holder; + typedef container_detail::integral_constant + ::value > alloc_version; + boost::container::container_detail::vector_alloc_holder m_holder; /// @cond typedef container_detail::vector_alloc_holder base_t; typedef allocator_traits allocator_traits_type; @@ -566,9 +581,6 @@ class vector 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; /// @endcond @@ -609,8 +621,7 @@ class vector explicit vector(size_type n) : m_holder(n) { - this->priv_first_allocation_fill - (container_detail::insert_default_constructed_n_proxy (this->m_holder.alloc()), n); + boost::container::uninitialized_default_alloc_n(this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector @@ -623,8 +634,8 @@ class vector vector(size_type n, const T& value) : m_holder(n) { - this->priv_first_allocation_fill - (container_detail::insert_n_copies_proxy (this->m_holder.alloc(), value), n); + boost::container::uninitialized_fill_alloc_n + (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector that will use a copy of allocator a @@ -637,8 +648,8 @@ class vector 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); + boost::container::uninitialized_fill_alloc_n + (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector @@ -676,9 +687,9 @@ class vector vector(const vector &x) : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) { - this->priv_first_allocation_fill - (container_detail::insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); + ::boost::container::uninitialized_copy_or_move_alloc_n_source + ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) + , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor. Moves mx's resources to *this. @@ -717,9 +728,9 @@ class vector vector(const vector &x, const allocator_type &a) : m_holder(a, x.size()) { - this->priv_first_allocation_fill - (container_detail::insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); + ::boost::container::uninitialized_copy_or_move_alloc_n_source + ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) + , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor using the specified allocator. @@ -737,10 +748,11 @@ class vector } else{ const size_type n = mx.size(); - this->m_holder.first_allocation(n); - this->priv_first_allocation_fill - (container_detail::move_insert_range_proxy - (this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start())), n); + this->m_holder.first_allocation_same_allocator_type(n); + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start()) + , n, container_detail::to_raw_pointer(this->m_holder.start())); + this->m_holder.m_size = n; } } @@ -767,17 +779,7 @@ class vector vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) { if (&x != this){ - allocator_type &this_alloc = this->m_holder.alloc(); - const allocator_type &x_alloc = x.m_holder.alloc(); - container_detail::bool_ flag; - if(flag && this_alloc != x_alloc){ - this->clear(); - this->shrink_to_fit(); - } - container_detail::assign_alloc(this_alloc, x_alloc, flag); - 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)); + this->priv_copy_assign(boost::move(x), alloc_version()); } return *this; } @@ -794,25 +796,7 @@ class vector //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable::value);) BOOST_CONTAINER_NOEXCEPT { - if (&x != this){ - allocator_type &this_alloc = this->m_holder.alloc(); - allocator_type &x_alloc = x.m_holder.alloc(); - //If allocators are equal we can just swap pointers - if(this_alloc == x_alloc){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - this->m_holder.swap(x.m_holder); - //Move allocator if needed - container_detail::bool_ flag; - container_detail::move_alloc(this_alloc, x_alloc, flag); - } - //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.start())) - , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size))); - } - } + this->priv_move_assign(boost::move(x), alloc_version()); return *this; } @@ -829,8 +813,7 @@ class vector 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))); + this->priv_move_assign(boost::move(x), alloc_version()); return *this; } @@ -1259,8 +1242,8 @@ class vector } else{ typedef container_detail::insert_emplace_proxy type; - this->priv_forward_range_insert_at_end - (1, type(this->m_holder.alloc(), ::boost::forward(args)...), alloc_version()); + this->priv_forward_range_insert_no_capacity + (this->cend().get_ptr(), 1, type(this->m_holder.alloc(), ::boost::forward(args)...), alloc_version()); } } @@ -1300,7 +1283,8 @@ 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_at_end(1, proxy, alloc_version()); \ + this->priv_forward_range_insert_no_capacity \ + (this->cend().get_ptr(), 1, proxy, alloc_version()); \ } \ } \ \ @@ -1482,9 +1466,6 @@ class vector { //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 @@ -1531,6 +1512,125 @@ class vector private: + template + void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value && + !container_detail::is_same::value + >::type * = 0) + { + if(this->capacity() < x.size()){ + throw_bad_alloc(); + } + this->priv_move_assign_impl(boost::move(x), AllocVersion()); + } + + template + void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value || + container_detail::is_same::value + >::type * = 0) + { + this->priv_move_assign_impl(boost::move(x), AllocVersion()); + } + + template + void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value + >::type * = 0) + { + T* const this_start = container_detail::to_raw_pointer(m_holder.start()); + T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); + const size_type this_sz = m_holder.m_size; + const size_type other_sz = static_cast(x.m_holder.m_size); + if (this_sz < other_sz){ + move_n(other_start, this_sz, this_start); // may throw + uninitialized_move_alloc_n( this->m_holder.alloc(), other_start + this_sz + , other_sz - this_sz, this_start + this_sz); // may throw + } + else + { + move_n(other_start, other_sz, this_start); + destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz); + } + this->m_holder.m_size = other_sz; + } + + template + void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value + >::type * = 0) + { + //for move constructor, no aliasing (&x != this) is assummed. + allocator_type &this_alloc = this->m_holder.alloc(); + allocator_type &x_alloc = x.m_holder.alloc(); + //If allocators are equal we can just swap pointers + if(this_alloc == x_alloc){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + this->m_holder.swap(x.m_holder); + //Move allocator if needed + container_detail::bool_ flag; + container_detail::move_alloc(this_alloc, x_alloc, flag); + } + //If unequal allocators, then do a one by one move + else{ + //TO-DO: optimize this + 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))); + } + } + + template + void priv_copy_assign(const vector &x, AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value + >::type * = 0) + { + T* const this_start = container_detail::to_raw_pointer(m_holder.start()); + T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); + const size_type this_sz = m_holder.m_size; + const size_type other_sz = static_cast(x.m_holder.m_size); + if (this_sz < other_sz){ + copy_or_move_n(other_start, this_sz, this_start); // may throw + uninitialized_copy_or_move_alloc_n( this->m_holder.alloc(), other_start + this_sz + , other_sz - this_sz, this_start + this_sz); // may throw + } + else + { + copy_or_move_n(other_start, other_sz, this_start); + destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz); + } + this->m_holder.m_size = other_sz; + } + + template + void priv_copy_assign(const vector &x, AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value + >::type * = 0) + { + allocator_type &this_alloc = this->m_holder.alloc(); + const allocator_type &x_alloc = x.m_holder.alloc(); + container_detail::bool_ flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + this->shrink_to_fit(); + } + container_detail::assign_alloc(this_alloc, x_alloc, flag); + 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)); + } + void priv_reserve(size_type, allocator_v0) { throw_bad_alloc(); @@ -1540,20 +1640,17 @@ class vector { //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); + T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); + const size_type sz = m_holder.m_size; + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) ); + destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + this->m_holder.start(p); + this->m_holder.capacity(new_cap); } void priv_reserve(size_type new_cap, allocator_v2) @@ -1575,14 +1672,13 @@ class vector #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){ + //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_expand_bwd; #endif @@ -1595,26 +1691,28 @@ class vector } //New buffer else{ + //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(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->m_holder.start()) - , 0 - , proxy); + T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); + const size_type sz = m_holder.m_size; + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) ); + destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + this->m_holder.start(ret.first); + this->m_holder.capacity(real_cap); } } } template - void priv_first_allocation_fill(Proxy proxy, size_type n) + void priv_uninitialized_fill(Proxy proxy, size_type n) const { //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; + //m_holder.size was already initialized to n in vector_alloc_holder's constructor } void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT @@ -1644,19 +1742,35 @@ class vector , ::boost::forward(x)), alloc_version()); } - template - void priv_push_back(BOOST_FWD_REF(U) x) + void priv_push_back(const T &x) { 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.start() + this->m_holder.m_size) - , ::boost::forward(x) ); + , x ); ++this->m_holder.m_size; } else{ - this->priv_insert(this->cend(), ::boost::forward(x)); + container_detail::insert_copy_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_no_capacity(this->cend().get_ptr(), 1, proxy, alloc_version()); + } + } + + void priv_push_back(BOOST_RV_REF(T) x) + { + 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.start() + this->m_holder.m_size) + , ::boost::move(x) ); + ++this->m_holder.m_size; + } + else{ + container_detail::insert_move_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_no_capacity(this->cend().get_ptr(), 1, proxy, alloc_version()); } } @@ -1712,23 +1826,28 @@ class vector } } + template + iterator priv_forward_range_insert_no_capacity + (const pointer &pos, const size_type, const InsertionProxy , allocator_v0) + { + throw_bad_alloc(); + return iterator(pos); + } + template iterator priv_forward_range_insert (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.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{ + if (n > remaining){ //This will trigger an error throw_bad_alloc(); } - + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } @@ -1739,40 +1858,49 @@ class vector //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{ + if (n > remaining){ //This will trigger an error throw_bad_alloc(); } - + this->priv_range_insert_at_end_expand_forward(n, insert_range_proxy); return this->end(); } + template + iterator priv_forward_range_insert_no_capacity + (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 n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + + 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 (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){ + const size_type n_pos = pos - this->m_holder.start(); this->priv_range_insert_expand_forward (raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); } 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 this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); } - return iterator(this->m_holder.start() + n_pos); } template @@ -1782,61 +1910,73 @@ class vector return this->priv_forward_range_insert(this->cend().get_ptr(), n, insert_range_proxy, allocator_v1()); } + template + iterator priv_forward_range_insert_no_capacity + (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 n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + + 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); + } + //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); + } + } + //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, raw_pos, n, insert_range_proxy); + } + + return iterator(this->m_holder.start() + n_pos); + } + 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); - } - //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); - } - } - //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, raw_pos, n, insert_range_proxy); - } + return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); } else{ //Expand forward + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); } - - return iterator(this->m_holder.start() + n_pos); } template @@ -1979,7 +2119,8 @@ class vector //Case B: else if((first_pos + shift_count) >= limit_pos){ //All uninitialized_moved - ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); + ::boost::container::uninitialized_move_alloc + (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); hole_size = last_pos + shift_count - limit_pos; } //Case C: diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 584f8ab..082bf1d 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -59,6 +59,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "throw_exception_test", "thr ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "static_vector_test", "static_vector_test.vcproj", "{58E1C1C3-096A-84FE-4FA2-D6BA79201C02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_static_vector", "bench_static_vector.vcproj", "{58E1C1C3-096A-84FE-4FA2-D6BA79201C02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -127,6 +135,14 @@ Global {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Debug.Build.0 = Debug|Win32 {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Release.ActiveCfg = Release|Win32 {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Release.Build.0 = Release|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.ActiveCfg = Debug|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.Build.0 = Debug|Win32 + {58E1C1C3-096A-84F0-4FA2-D6BA79201C02}.Release.ActiveCfg = Release|Win32 + {58E1C1C3-096A-84F0-4FA2-D6BA79201C02}.Release.Build.0 = Release|Win32 + {58E1C1C3-096A-84F1-4FA2-D6BA79201C02}.Debug.ActiveCfg = Debug|Win32 + {58E1C1C3-096A-84F1-4FA2-D6BA79201C02}.Debug.Build.0 = Debug|Win32 + {58E1C1C3-096A-84F2-4FA2-D6BA79201C02}.Release.ActiveCfg = Release|Win32 + {58E1C1C3-096A-84F2-4FA2-D6BA79201C02}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 5deba8d..9f42b17 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -172,6 +172,9 @@ + + @@ -221,6 +224,9 @@ + + @@ -325,6 +331,26 @@ + + + + + + + + + + + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index af84010..25add18 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,7 +21,7 @@ rule test_all for local fileb in [ glob *.cpp ] { - all_rules += [ run $(fileb) + all_rules += [ run $(fileb) /boost/timer//boost_timer /boost/system//boost_system /boost/thread//boost_thread : # additional args : # test-files : # requirements diff --git a/test/movable.hpp b/test/movable.hpp deleted file mode 100644 index 3076865..0000000 --- a/test/movable.hpp +++ /dev/null @@ -1,92 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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/movable_int.hpp b/test/movable_int.hpp index 65fa473..1daf02a 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -53,23 +53,26 @@ class movable_int movable_int & operator= (int i) { this->m_int = i; return *this; } - bool operator ==(const movable_int &mi) const - { return this->m_int == mi.m_int; } + ~movable_int() + { this->m_int = 0; } - bool operator !=(const movable_int &mi) const - { return this->m_int != mi.m_int; } + friend bool operator ==(const movable_int &l, const movable_int &r) + { return l.m_int == r.m_int; } - bool operator <(const movable_int &mi) const - { return this->m_int < mi.m_int; } + friend bool operator !=(const movable_int &l, const movable_int &r) + { return l.m_int != r.m_int; } - bool operator <=(const movable_int &mi) const - { return this->m_int <= mi.m_int; } + friend bool operator <(const movable_int &l, const movable_int &r) + { return l.m_int < r.m_int; } - bool operator >=(const movable_int &mi) const - { return this->m_int >= mi.m_int; } + friend bool operator <=(const movable_int &l, const movable_int &r) + { return l.m_int <= r.m_int; } - bool operator >(const movable_int &mi) const - { return this->m_int > mi.m_int; } + friend bool operator >=(const movable_int &l, const movable_int &r) + { return l.m_int >= r.m_int; } + + friend bool operator >(const movable_int &l, const movable_int &r) + { return l.m_int > r.m_int; } int get_int() const { return m_int; } @@ -84,6 +87,9 @@ class movable_int int m_int; }; +inline movable_int produce_movable_int() +{ return movable_int(); } + template std::basic_ostream & operator<< (std::basic_ostream & os, movable_int const & p) @@ -93,7 +99,6 @@ std::basic_ostream & operator<< return os; } - template<> struct is_copyable { @@ -121,6 +126,9 @@ class movable_and_copyable_int : m_int(mmi.m_int) { mmi.m_int = 0; } + ~movable_and_copyable_int() + { this->m_int = 0; } + movable_and_copyable_int &operator= (BOOST_COPY_ASSIGN_REF(movable_and_copyable_int) mi) { this->m_int = mi.m_int; return *this; } @@ -130,23 +138,23 @@ class movable_and_copyable_int movable_and_copyable_int & operator= (int i) { this->m_int = i; return *this; } - bool operator ==(const movable_and_copyable_int &mi) const - { return this->m_int == mi.m_int; } + friend bool operator ==(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int == r.m_int; } - bool operator !=(const movable_and_copyable_int &mi) const - { return this->m_int != mi.m_int; } + friend bool operator !=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int != r.m_int; } - bool operator <(const movable_and_copyable_int &mi) const - { return this->m_int < mi.m_int; } + friend bool operator <(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int < r.m_int; } - bool operator <=(const movable_and_copyable_int &mi) const - { return this->m_int <= mi.m_int; } + friend bool operator <=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int <= r.m_int; } - bool operator >=(const movable_and_copyable_int &mi) const - { return this->m_int >= mi.m_int; } + friend bool operator >=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int >= r.m_int; } - bool operator >(const movable_and_copyable_int &mi) const - { return this->m_int > mi.m_int; } + friend bool operator >(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int > r.m_int; } int get_int() const { return m_int; } @@ -161,6 +169,9 @@ class movable_and_copyable_int int m_int; }; +inline movable_and_copyable_int produce_movable_and_copyable_int() +{ return movable_and_copyable_int(); } + template std::basic_ostream & operator<< (std::basic_ostream & os, movable_and_copyable_int const & p) @@ -194,23 +205,29 @@ class copyable_int copyable_int & operator= (int i) { this->m_int = i; return *this; } - bool operator ==(const copyable_int &mi) const - { return this->m_int == mi.m_int; } + copyable_int & operator= (const copyable_int &ci) + { this->m_int = ci.m_int; return *this; } - bool operator !=(const copyable_int &mi) const - { return this->m_int != mi.m_int; } + ~copyable_int() + { this->m_int = 0; } - bool operator <(const copyable_int &mi) const - { return this->m_int < mi.m_int; } + friend bool operator ==(const copyable_int &l, const copyable_int &r) + { return l.m_int == r.m_int; } - bool operator <=(const copyable_int &mi) const - { return this->m_int <= mi.m_int; } + friend bool operator !=(const copyable_int &l, const copyable_int &r) + { return l.m_int != r.m_int; } - bool operator >=(const copyable_int &mi) const - { return this->m_int >= mi.m_int; } + friend bool operator <(const copyable_int &l, const copyable_int &r) + { return l.m_int < r.m_int; } - bool operator >(const copyable_int &mi) const - { return this->m_int > mi.m_int; } + friend bool operator <=(const copyable_int &l, const copyable_int &r) + { return l.m_int <= r.m_int; } + + friend bool operator >=(const copyable_int &l, const copyable_int &r) + { return l.m_int >= r.m_int; } + + friend bool operator >(const copyable_int &l, const copyable_int &r) + { return l.m_int > r.m_int; } int get_int() const { return m_int; } @@ -225,6 +242,9 @@ class copyable_int int m_int; }; +inline copyable_int produce_copyable_int() +{ return copyable_int(); } + template std::basic_ostream & operator<< (std::basic_ostream & os, copyable_int const & p) @@ -254,6 +274,9 @@ class non_copymovable_int : m_int(a) {} + ~non_copymovable_int() + { m_int = 0; } + bool operator ==(const non_copymovable_int &mi) const { return this->m_int == mi.m_int; } diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp index f12e7e1..f616174 100644 --- a/test/static_vector_test.cpp +++ b/test/static_vector_test.cpp @@ -19,31 +19,35 @@ namespace test { //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(); + 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&) { \ - } \ +#define BOOST_TEST_THROW( S, E ) \ + try { \ + S; \ + ::boost::container::test::throw_failed_impl \ + (#E, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ + } \ + catch(E const&) { \ + } \ + catch(...) { \ + ::boost::container::test::throw_failed_impl \ + (#E, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ + } \ // // 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 + void throw_exception(std::exception const & e){}; // user defined } // namespace boost #endif // BOOST_NO_EXCEPTIONS @@ -69,735 +73,734 @@ 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); + 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 ); + 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); + 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 ); + 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)); - } + 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); + 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 ); + 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)); - } + 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; + static_vector s; - s.resize(n); - BOOST_TEST(s.size() == n); - BOOST_TEST(s.capacity() == N); + 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 ); + 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)); - } + 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; + static_vector s; - s.resize(n, v); - BOOST_TEST(s.size() == n); - BOOST_TEST(s.capacity() == N); + 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 ); + 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)); - } + 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; + static_vector s; - BOOST_TEST(s.size() == 0); + BOOST_TEST(s.size() == 0); #ifndef BOOST_NO_EXCEPTIONS - BOOST_TEST_THROW( s.at(0), std::out_of_range ); + 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); + 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 ); + 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)); - } + 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; + static_vector s; - for ( size_t i = 0 ; i < N ; ++i ) - { - T t(i); - s.push_back(t); - } + 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); + 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 ); + 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()); - } + 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); + 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()); - } + { + 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; + 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()); - } + 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); + // 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()); - } + // 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); + 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; + static_vector s; + std::vector v; - for ( size_t i = 0 ; i < N ; ++i ) - { - s.push_back(T(i)); - v.push_back(T(i)); - } + 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()); + 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()); + 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()); + 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; + static_vector s; + typedef typename static_vector::iterator It; - for ( size_t i = 0 ; i < N ; ++i ) - s.push_back(T(i)); + 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)); - } - } + // 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); + 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); + 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); + 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)); - } + 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; + size_t h = N/2; - static_vector s, ss; - std::vector v; - std::list l; + static_vector s, ss; + std::vector v; + std::list l; - typedef typename static_vector::iterator It; + 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)); - } + 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); + // 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); + 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 v(5u, T(0)); - static_vector s; - BOOST_TEST(s.size() == 0); - BOOST_TEST(s.capacity() == 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 &){} + 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)); + 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 &){} + 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; + { + 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)); - } + 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); + 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; + 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)); - } + 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)); + 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)); + 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)); + } + } + { + typedef static_vector small_vector_t; + static_vector v(N, T(0)); + small_vector_t 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 &) {} + 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)); + BOOST_TEST_THROW(small_vector_t s2(boost::move(v)), std::bad_alloc); #endif // BOOST_NO_EXCEPTIONS - } + } } template void test_emplace_0p() { - //emplace_back() - { - static_vector v; + //emplace_back() + { + static_vector v; - for (int i = 0 ; i < int(N) ; ++i ) - v.emplace_back(); - BOOST_TEST(v.size() == N); + 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); + BOOST_TEST_THROW(v.emplace_back(), std::bad_alloc); #endif - } + } } template void test_emplace_2p() { - //emplace_back(pos, int, int) - { - static_vector v; + //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); + 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); + 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)); - } + 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; + // emplace(pos, int, int) + { + typedef typename static_vector::iterator It; - int h = N / 2; + int h = N / 2; - static_vector v; - for ( int i = 0 ; i < h ; ++i ) - v.emplace_back(i, 100 + i); + 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)); - } - } + 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; + typedef static_vector V; - 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); + 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); + using boost::container::test::movable_and_copyable_int; + using boost::container::test::produce_movable_and_copyable_int; + 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_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_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_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_movable_and_copyable_int()); - 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_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_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_movable_and_copyable_int()); - 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_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_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_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_movable_and_copyable_int()); - test_iterators_nd(); - test_iterators_nd(); - test_iterators_nd(); - BOOST_TEST(counting_value::count() == 0); - test_iterators_nd(); - test_iterators_nd(); + 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_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_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_movable_and_copyable_int()); - 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_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_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_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_0p(); + BOOST_TEST(counting_value::count() == 0); - test_emplace_2p(); - 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(); + 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(movable_and_copyable_int(50)); + return boost::report_errors(); } #include diff --git a/test/static_vector_test.hpp b/test/static_vector_test.hpp index 3dfe697..f2b3a65 100644 --- a/test/static_vector_test.hpp +++ b/test/static_vector_test.hpp @@ -14,7 +14,7 @@ #include #include -#include "movable.hpp" +#include "movable_int.hpp" using namespace boost::container; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 318e339..3771eaf 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -216,7 +216,12 @@ int vector_test() stdvector->push_back(int(1)); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } - { //push_back with enough capacity + + { //test back() + const IntType test_this(1); + if(test_this != boostvector->back()) return 1; + } + { //pop_back with enough capacity boostvector->pop_back(); boostvector->pop_back(); stdvector->pop_back();