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..f36e145 --- /dev/null +++ b/bench/bench_static_vector.cpp @@ -0,0 +1,146 @@ +// 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:" << std::endl; + cpu_times time_varray = time_it,N > >(); + + std::cout << "boost::container::static_vector benchmark" << std::endl; + cpu_times time_boost_static_vector = time_it,N > >(); + + std::cout << "boost::container::vector benchmark" << std::endl; + cpu_times time_boost_vector = time_it > >(); + + std::cout << "std::vector benchmark" << std::endl; + 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/Jamfile.v2 b/doc/Jamfile.v2 index 5c470ce..fe7f054 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -50,6 +50,8 @@ boostbook standalone : html:boost.root=../../../.. html:boost.libraries=../../../../libs/libraries.htm + html:img.src.path=../../../../doc/html/ + xhtml:img.src.path=../../../../doc/html/ generate.section.toc.level=3 chunk.first.sections=1 pdf:img.src.path=$(images_location)/ diff --git a/doc/container.qbk b/doc/container.qbk index 7dbc319..daec5ce 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -189,6 +189,49 @@ Finally, we can just compile, link, and run! [endsect] +[section:exception_handling Boost.Container and C++ exceptions] + +In some environments, such as game development or embedded systems, C++ exceptions are disabled or a customized error handling is needed. +According to document [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html N2271 EASTL -- Electronic Arts Standard Template Library] +exceptions can be disabled for several reasons: + +* ["['Exception handling incurs some kind of cost in all compiler implementations, including those that avoid + the cost during normal execution. However, in some cases this cost may arguably offset the cost of the code that it is replacing.]] +* ["['Exception handling is often agreed to be a superior solution for handling a large range of function return values. However, + avoiding the creation of functions that need large ranges of return values is superior to using exception handling to handle such values.]] +* ["['Using exception handling correctly can be difficult in the case of complex software.]] +* ["['The execution of throw and catch can be significantly expensive with some implementations.]] +* ["['Exception handling violates the don't-pay-for-what-you-don't-use design of C++, as it incurs overhead in any non-leaf function that + has destructible stack objects regardless of whether they use exception handling.]] +* ["['The approach that game software usually takes is to avoid the need for exception handling where possible; avoid the possibility + of circumstances that may lead to exceptions. For example, verify up front that there is enough memory for a subsystem to do its job + instead of trying to deal with the problem via exception handling or any other means after it occurs.]] +* ["['However, some game libraries may nevertheless benefit from the use of exception handling. It's best, however, + if such libraries keep the exception handling internal lest they force their usage of exception handling on the rest of the application.]] + +In order to support environments without C++ exception support or environments with special error handling needs, +[*Boost.Container] changes error signalling behaviour when `BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS` or `BOOST_NO_EXCEPTIONS` +is defined. The former shall be defined by the user and the latter can be either defined by the user or implicitly defined by [*Boost.Confg] +when the compiler has been invoked with the appropriate flag (like `-fno-exceptions` in GCC). + +When dealing with user-defined classes, (e.g. when constructing user-defined classes): + +* If `BOOST_NO_EXCEPTIONS` is defined, the library avoids using `try`/`catch`/`throw` statements. The class writer must handle and + propagate error situations internally as no error will be propagated through [*Boost.Container]. +* If `BOOST_NO_EXCEPTIONS` is *not* defined, the library propagates exceptions offering the exception guarantees detailed in the documentation. + +When the library needs to throw an exception (such as `out_of_range` when an incorrect index is used in `vector::at`)], the library calls +a throw callback declared in ``: + +* If `BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS` is defined, then the programmer must provide its own definition for all + `throw_xxx` functions. Those functions can't return, they must throw an exception or call `std::exit` or `std::abort`. +* Else if `BOOST_NO_EXCEPTIONS` is defined, a `BOOST_ASSERT_MSG` assertion is triggered + (see [@http://www.boost.org/libs/utility/assert.html Boost.Assert] for more information). + If this assertion returns, then `std::abort` is called. +* Else, an appropriate standard library exception is thrown (like `std::out_of_range`). + +[endsect] + [section:non_standard_containers Non-standard containers] [section:stable_vector ['stable_vector]] @@ -210,7 +253,7 @@ can a stable design approach the behavior of `vector` (random access iterators, insertion/deletion, minimal memory overhead, etc.)? The following image describes the layout of a possible data structure upon which to base the design of a stable vector: -[$images/stable_vector.png [width 50%] [align center] ] +[$../../libs/container/doc/html/images/stable_vector.png [width 50%] [align center] ] Each element is stored in its own separate node. All the nodes are referenced from a contiguous array of pointers, but also every node contains an "up" pointer referring back to the associated array cell. This up pointer is the key element @@ -569,6 +612,8 @@ use [*Boost.Container]? There are several reasons for that: usually implies a no-throw guarantee (if predicate's or allocator's default constructor doesn't throw). * Small string optimization for [classref boost::container::basic_string basic_string]. * New extensions beyond the standard based on user feedback to improve code performance. +* You need a portable implementation that works when compiling without exceptions support or + you need to customize the error handling when a container needs to signall an exceptional error. [endsect] @@ -614,6 +659,17 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_54_00 Boost 1.54 Release] + +* Speed improvements in `vector` constructors/copy/move/swap, dispatching to memcpy when possible. +* 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/8118 #8118], + [@https://svn.boost.org/trac/boost/ticket/8294 #8294]. + +[endsect] + [section:release_notes_boost_1_53_00 Boost 1.53 Release] * Fixed bug [@https://svn.boost.org/trac/boost/ticket/7650 #7650]. diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css deleted file mode 100644 index 2146334..0000000 --- a/doc/html/boostbook.css +++ /dev/null @@ -1,537 +0,0 @@ -/*============================================================================= - Copyright (c) 2004 Joel de Guzman - - 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) -=============================================================================*/ - -/*============================================================================= - Body defaults -=============================================================================*/ - - body - { - margin: 1em; - font-family: sans-serif; - } - -/*============================================================================= - Paragraphs -=============================================================================*/ - - p - { - text-align: left; - font-size: 10pt; - line-height: 1.15; - } - -/*============================================================================= - Program listings -=============================================================================*/ - - /* Code on paragraphs */ - p tt.computeroutput - { - font-size: 10pt; - } - - pre.synopsis - { - font-size: 10pt; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - .programlisting, - .screen - { - font-size: 10pt; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - -/*============================================================================= - Headings -=============================================================================*/ - - h1, h2, h3, h4, h5, h6 - { - text-align: left; - margin: 1em 0em 0.5em 0em; - font-weight: bold; - } - - h1 { font: 140% } - h2 { font: bold 140% } - h3 { font: bold 130% } - h4 { font: bold 120% } - h5 { font: italic 110% } - h6 { font: italic 100% } - - /* Top page titles */ - title, - h1.title, - h2.title - h3.title, - h4.title, - h5.title, - h6.title, - .refentrytitle - { - font-weight: bold; - margin-bottom: 1pc; - } - - h1.title { font-size: 140% } - h2.title { font-size: 140% } - h3.title { font-size: 130% } - h4.title { font-size: 120% } - h5.title { font-size: 110% } - h6.title { font-size: 100% } - - .section h1 - { - margin: 0em 0em 0.5em 0em; - font-size: 140%; - } - - .section h2 { font-size: 140% } - .section h3 { font-size: 130% } - .section h4 { font-size: 120% } - .section h5 { font-size: 110% } - .section h6 { font-size: 100% } - - /* Code on titles */ - h1 tt.computeroutput { font-size: 140% } - h2 tt.computeroutput { font-size: 140% } - h3 tt.computeroutput { font-size: 130% } - h4 tt.computeroutput { font-size: 120% } - h5 tt.computeroutput { font-size: 110% } - h6 tt.computeroutput { font-size: 100% } - -/*============================================================================= - Author -=============================================================================*/ - - h3.author - { - font-size: 100% - } - -/*============================================================================= - Lists -=============================================================================*/ - - li - { - font-size: 10pt; - line-height: 1.3; - } - - /* Unordered lists */ - ul - { - text-align: left; - } - - /* Ordered lists */ - ol - { - text-align: left; - } - -/*============================================================================= - Links -=============================================================================*/ - - a - { - text-decoration: none; /* no underline */ - } - - a:hover - { - text-decoration: underline; - } - -/*============================================================================= - Spirit style navigation -=============================================================================*/ - - .spirit-nav - { - text-align: right; - } - - .spirit-nav a - { - color: white; - padding-left: 0.5em; - } - - .spirit-nav img - { - border-width: 0px; - } - -/*============================================================================= - Table of contents -=============================================================================*/ - - .toc - { - margin: 1pc 4% 0pc 4%; - padding: 0.1pc 1pc 0.1pc 1pc; - font-size: 10pt; - line-height: 1.15; - } - - .toc-main - { - width: 600; - text-align: center; - margin: 1pc 1pc 1pc 10%; - padding: 2pc 1pc 3pc 1pc; - line-height: 0.1; - } - - .boost-toc - { - float: right; - padding: 0.5pc; - } - -/*============================================================================= - Tables -=============================================================================*/ - - .table-title, - div.table p.title - { - margin-left: 4%; - padding-right: 0.5em; - padding-left: 0.5em; - } - - .informaltable table, - .table table - { - width: 92%; - margin-left: 4%; - margin-right: 4%; - } - - div.informaltable table, - div.table table - { - padding: 4px; - } - - /* Table Cells */ - div.informaltable table tr td, - div.table table tr td - { - padding: 0.5em; - text-align: left; - } - - div.informaltable table tr th, - div.table table tr th - { - padding: 0.5em 0.5em 0.5em 0.5em; - border: 1pt solid white; - font-size: 120%; - } - -/*============================================================================= - Blurbs -=============================================================================*/ - - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - font-size: 10pt; - line-height: 1.2; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - p.blurb img - { - padding: 1pt; - } - -/*============================================================================= - Variable Lists -=============================================================================*/ - - span.term - { - font-weight: bold; - font-size: 10pt; - } - - div.variablelist table tbody tr td - { - text-align: left; - vertical-align: top; - padding: 0em 2em 0em 0em; - font-size: 10pt; - } - - div.variablelist table tbody tr td p - { - margin: 0em 0em 0.5em 0em; - } - - /* Make the terms in definition lists bold */ - div.variablelist dl dt - { - font-weight: bold; - font-size: 10pt; - } - - div.variablelist dl dd - { - margin: 1em 0em 1em 2em; - font-size: 10pt; - } - -/*============================================================================= - Misc -=============================================================================*/ - - /* Title of books and articles in bibliographies */ - span.title - { - font-style: italic; - } - - span.underline - { - text-decoration: underline; - } - - span.strikethrough - { - text-decoration: line-through; - } - - /* Copyright, Legal Notice */ - div div.legalnotice p - { - font-size: 8pt; - text-align: left - } - -/*============================================================================= - Colors -=============================================================================*/ - - @media screen - { - /* Links */ - a - { - color: #0C7445; - } - - a:visited - { - color: #663974; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, - h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, - h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited - { - text-decoration: none; /* no underline */ - color: #000000; - } - - /* Syntax Highlighting */ - .keyword { color: #0000AA; } - .identifier { color: #000000; } - .special { color: #707070; } - .preprocessor { color: #402080; } - .char { color: teal; } - .comment { color: #800000; } - .string { color: teal; } - .number { color: teal; } - .white_bkd { background-color: #E8FBE9; } - .dk_grey_bkd { background-color: #A0DAAC; } - - /* Copyright, Legal Notice */ - .copyright - { - color: #666666; - font-size: small; - } - - div div.legalnotice p - { - color: #666666; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - .programlisting, - .screen - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Blurbs */ - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc-main - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - div.informaltable table tr th, - div.table table tr th - { - background-color: #E3F9E4; - border: 1px solid #DCDCDC; - } - - /* Misc */ - span.highlight - { - color: #00A000; - } - } - - @media print - { - /* Links */ - a - { - color: black; - } - - a:visited - { - color: black; - } - - .spirit-nav - { - display: none; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid gray; - background-color: #FAFFFB; - } - - .programlisting, - .screen - { - border: 1px solid gray; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc-main - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - .informaltable table, - .table table - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - border-collapse: collapse; - background-color: #FAFFFB; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - div.informaltable table tr th, - div.table table tr th - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - /* Misc */ - span.highlight - { - font-weight: bold; - } - } diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png deleted file mode 100644 index 764bf4f..0000000 Binary files a/doc/html/images/blank.png and /dev/null differ diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png deleted file mode 100644 index 5b7809c..0000000 Binary files a/doc/html/images/caution.png and /dev/null differ diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png deleted file mode 100644 index 0084708..0000000 Binary files a/doc/html/images/draft.png and /dev/null differ diff --git a/doc/html/images/home.png b/doc/html/images/home.png deleted file mode 100644 index 5584aac..0000000 Binary files a/doc/html/images/home.png and /dev/null differ diff --git a/doc/html/images/important.png b/doc/html/images/important.png deleted file mode 100644 index 12c90f6..0000000 Binary files a/doc/html/images/important.png and /dev/null differ diff --git a/doc/html/images/next.png b/doc/html/images/next.png deleted file mode 100644 index 59800b4..0000000 Binary files a/doc/html/images/next.png and /dev/null differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png deleted file mode 100644 index d0c3c64..0000000 Binary files a/doc/html/images/note.png and /dev/null differ diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png deleted file mode 100644 index d88a40f..0000000 Binary files a/doc/html/images/prev.png and /dev/null differ diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png deleted file mode 100644 index 5c4aab3..0000000 Binary files a/doc/html/images/tip.png and /dev/null differ diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png deleted file mode 100644 index 6ffad17..0000000 Binary files a/doc/html/images/toc-blank.png and /dev/null differ diff --git a/doc/html/images/toc-minus.png b/doc/html/images/toc-minus.png deleted file mode 100644 index abbb020..0000000 Binary files a/doc/html/images/toc-minus.png and /dev/null differ diff --git a/doc/html/images/toc-plus.png b/doc/html/images/toc-plus.png deleted file mode 100644 index 941312c..0000000 Binary files a/doc/html/images/toc-plus.png and /dev/null differ diff --git a/doc/html/images/up.png b/doc/html/images/up.png deleted file mode 100644 index 17d9c3e..0000000 Binary files a/doc/html/images/up.png and /dev/null differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png deleted file mode 100644 index 1c33db8..0000000 Binary files a/doc/html/images/warning.png and /dev/null differ diff --git a/doc/html/reference.css b/doc/html/reference.css deleted file mode 100644 index 1bf6b68..0000000 --- a/doc/html/reference.css +++ /dev/null @@ -1,12 +0,0 @@ -/*============================================================================= - Copyright (c) 2004 Joel de Guzman - - 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) -=============================================================================*/ -PRE.synopsis { - background-color: #e0ffff; - border: thin solid blue; - padding: 1em -} diff --git a/proj/vc7ide/bench_static_vector.vcproj b/proj/vc7ide/bench_static_vector.vcproj new file mode 100644 index 0000000..a518d54 --- /dev/null +++ b/proj/vc7ide/bench_static_vector.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 68beb93..082bf1d 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -55,6 +55,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_tab ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "throw_exception_test", "throw_exception_test.vcproj", "{5A8D91E0-FA57-284F-84FE-D3A6BA792002}" + 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 @@ -119,6 +131,18 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {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 5c89b16..185a5c0 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -95,96 +95,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -218,9 +137,15 @@ + + + + @@ -260,6 +185,9 @@ + + @@ -316,6 +244,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/static_vector_test.vcproj b/proj/vc7ide/static_vector_test.vcproj new file mode 100644 index 0000000..2ada060 --- /dev/null +++ b/proj/vc7ide/static_vector_test.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/throw_exception_test.vcproj b/proj/vc7ide/throw_exception_test.vcproj new file mode 100644 index 0000000..12b7bb8 --- /dev/null +++ b/proj/vc7ide/throw_exception_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/vector_test.vcproj b/proj/vc7ide/vector_test.vcproj index 270f5cf..1076c97 100644 --- a/proj/vc7ide/vector_test.vcproj +++ b/proj/vc7ide/vector_test.vcproj @@ -22,6 +22,7 @@ AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" MinimalRebuild="TRUE" + ExceptionHandling="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" TreatWChar_tAsBuiltInType="TRUE" diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 23a8e58..2889423 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -29,6 +29,7 @@ #include "emplace_test.hpp" #include "propagate_allocator_test.hpp" #include "vector_test.hpp" +#include using namespace boost::container; @@ -143,7 +144,7 @@ bool do_test() typedef deque MyCntDeque; typedef std::deque MyStdDeque; const int max = 100; - try{ + BOOST_TRY{ //Shared memory allocator must be always be initialized //since it has no default constructor MyCntDeque *cntdeque = new MyCntDeque; @@ -206,6 +207,20 @@ bool do_test() stddeque->insert(stddeque->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + for(int i = 0; i < 50; ++i){ + IntType move_me (i); + aux_vect[i] = boost::move(move_me); + } + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + cntdeque->insert(cntdeque->begin()+cntdeque->size() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stddeque->insert(stddeque->begin()+stddeque->size(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + for(int i = 0, j = static_cast(cntdeque->size()); i < j; ++i){ cntdeque->erase(cntdeque->begin()); stddeque->erase(stddeque->begin()); @@ -268,10 +283,13 @@ bool do_test() delete cntdeque; delete stddeque; } - catch(std::exception &ex){ + BOOST_CATCH(std::exception &ex){ + #ifndef BOOST_NO_EXCEPTIONS std::cout << ex.what() << std::endl; + #endif return false; } + BOOST_CATCH_END std::cout << std::endl << "Test OK!" << std::endl; return true; diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index ef95836..afdd042 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -26,11 +26,11 @@ #include #include #include +#include #include #include #include #include -#include #include //!\file @@ -314,15 +314,20 @@ class propagation_test_allocator friend bool operator!=(const propagation_test_allocator &, const propagation_test_allocator &) { return false; } + void swap(propagation_test_allocator &r) + { + ++this->swaps_; ++r.swaps_; + boost::container::swap_dispatch(this->id_, r.id_); + boost::container::swap_dispatch(this->ctr_copies_, r.ctr_copies_); + boost::container::swap_dispatch(this->ctr_moves_, r.ctr_moves_); + boost::container::swap_dispatch(this->assign_copies_, r.assign_copies_); + boost::container::swap_dispatch(this->assign_moves_, r.assign_moves_); + boost::container::swap_dispatch(this->swaps_, r.swaps_); + } + friend void swap(propagation_test_allocator &l, propagation_test_allocator &r) { - ++l.swaps_; ++r.swaps_; - container_detail::do_swap(l.id_, r.id_); - container_detail::do_swap(l.ctr_copies_, r.ctr_copies_); - container_detail::do_swap(l.ctr_moves_, r.ctr_moves_); - container_detail::do_swap(l.assign_copies_, r.assign_copies_); - container_detail::do_swap(l.assign_moves_, r.assign_moves_); - container_detail::do_swap(l.swaps_, r.swaps_); + l.swap(r); } unsigned int id_; diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index a39aaf1..81bf016 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include //!\file @@ -112,9 +112,9 @@ class expand_bwd_test_allocator friend void swap(self_t &alloc1, self_t &alloc2) { - container_detail::do_swap(alloc1.mp_buffer, alloc2.mp_buffer); - container_detail::do_swap(alloc1.m_size, alloc2.m_size); - container_detail::do_swap(alloc1.m_offset, alloc2.m_offset); + boost::container::swap_dispatch(alloc1.mp_buffer, alloc2.mp_buffer); + boost::container::swap_dispatch(alloc1.m_size, alloc2.m_size); + boost::container::swap_dispatch(alloc1.m_offset, alloc2.m_offset); } //Experimental version 2 expand_bwd_test_allocator functions @@ -146,8 +146,8 @@ class expand_bwd_test_allocator return std::pair(mp_buffer, true); } else{ - assert(0); - throw std::bad_alloc(); + throw_bad_alloc(); + return std::pair(mp_buffer, true); } } diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index 0f06e23..c1f26e1 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -135,7 +135,7 @@ bool test_insert_with_expand_bwd() for(int iteration = 0; iteration < Iterations; ++iteration) { value_type *memory = new value_type[MemorySize]; - try { + BOOST_TRY { std::vector initial_data; initial_data.resize(InitialSize[iteration]); for(int i = 0; i < InitialSize[iteration]; ++i){ @@ -165,10 +165,11 @@ bool test_insert_with_expand_bwd() return false; } } - catch(...){ + BOOST_CATCH(...){ delete [](const_cast(memory)); - throw; + BOOST_RETHROW; } + BOOST_CATCH_END delete [](const_cast(memory)); } @@ -193,7 +194,7 @@ bool test_assign_with_expand_bwd() for(int iteration = 0; iteration initial_data; initial_data.resize(InitialSize[iteration]); @@ -227,10 +228,11 @@ bool test_assign_with_expand_bwd() return false; } } - catch(...){ + BOOST_CATCH(...){ delete [](const_cast::type*>(memory)); - throw; + BOOST_RETHROW; } + BOOST_CATCH_END delete [](const_cast::type*>(memory)); } diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index c476b13..5854b59 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -116,6 +116,9 @@ template class flat_multiset , std::allocator >; +//As flat container iterators are typedefs for vector::[const_]iterator, +//no need to explicit instantiate them + }} //boost::container diff --git a/test/heap_allocator_v1.hpp b/test/heap_allocator_v1.hpp index 56fc1a2..43603f7 100644 --- a/test/heap_allocator_v1.hpp +++ b/test/heap_allocator_v1.hpp @@ -28,7 +28,6 @@ #include #include #include -#include //!\file //!Describes an heap_allocator_v1 that allocates portions of fixed size @@ -134,7 +133,7 @@ class heap_allocator_v1 //!Swap segment manager. Does not throw. If each heap_allocator_v1 is placed in //!different memory segments, the result is undefined. friend void swap(self_t &alloc1, self_t &alloc2) - { detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); } + { boost::container::boost::container::swap_dispatch(alloc1.mp_mngr, alloc2.mp_mngr); } }; //!Equality test for same type of heap_allocator_v1 diff --git a/test/insert_test.hpp b/test/insert_test.hpp new file mode 100644 index 0000000..1d589f1 --- /dev/null +++ b/test/insert_test.hpp @@ -0,0 +1,74 @@ +#ifndef BOOST_CONTAINER_TEST_INSERT_TEST_HPP +#define BOOST_CONTAINER_TEST_INSERT_TEST_HPP + +// Copyright (C) 2013 Cromwell D. Enage +// 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) + +#include +#include +#include "check_equal_containers.hpp" + +namespace boost { +namespace container { +namespace test { + +template +void + test_insert_range( + std::deque &std_deque + , SeqContainer &seq_container + , std::deque const& input_deque + , std::size_t index + ) +{ + BOOST_TEST(CheckEqualContainers(&std_deque, &seq_container)); + + std_deque.insert( + std_deque.begin() + index + , input_deque.begin() + , input_deque.end() + ); + + seq_container.insert( + seq_container.begin() + index + , input_deque.begin() + , input_deque.end() + ); + BOOST_TEST(CheckEqualContainers(&std_deque, &seq_container)); +} + +template +bool test_range_insertion() +{ + int err_count = boost::report_errors(); + typedef typename SeqContainer::value_type value_type; + std::deque input_deque; + for (int element = -10; element < 10; ++element) + { + input_deque.push_back(element + 20); + } + + for (std::size_t i = 0; i <= input_deque.size(); ++i) + { + std::deque std_deque; + SeqContainer seq_container; + + for (int element = -10; element < 10; ++element) + { + std_deque.push_back(element); + seq_container.push_back(value_type(element)); + } + test_insert_range(std_deque, seq_container, input_deque, i); + } + + return err_count == boost::report_errors(); +} + + +} //namespace test { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_TEST_INSERT_TEST_HPP diff --git a/test/list_test.cpp b/test/list_test.cpp index 2abcdec..fca017f 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -32,6 +32,15 @@ template class boost::container::list >; +namespace container_detail { + +template class list_const_iterator + >::container_type::iterator >; +template class list_iterator + >::container_type::iterator>; + +} + }} typedef list MyList; diff --git a/test/list_test.hpp b/test/list_test.hpp index e1f0ec6..0ce580b 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -148,7 +148,7 @@ int list_test (bool copied_allocators_equal = true) const int max = 100; typedef list_push_data_function push_data_t; - try{ + BOOST_TRY{ MyBoostList *boostlist = new MyBoostList; MyStdList *stdlist = new MyStdList; @@ -338,9 +338,10 @@ int list_test (bool copied_allocators_equal = true) delete boostlist; delete stdlist; } - catch(...){ - throw; + BOOST_CATCH(...){ + BOOST_RETHROW; } + BOOST_CATCH_END return 0; } diff --git a/test/map_test.hpp b/test/map_test.hpp index 96ea05d..523eb37 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -44,7 +44,7 @@ int map_test () typedef typename MyStdMap::value_type StdPairType; const int max = 100; - try{ + BOOST_TRY{ MyBoostMap *boostmap = new MyBoostMap; MyStdMap *stdmap = new MyStdMap; MyBoostMultiMap *boostmultimap = new MyBoostMultiMap; @@ -179,14 +179,14 @@ int map_test () if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; - typename MyBoostMap::iterator it; + typename MyBoostMap::iterator it = boostmap->begin(); typename MyBoostMap::const_iterator cit = it; (void)cit; - boostmap->erase(boostmap->begin()++); - stdmap->erase(stdmap->begin()++); - boostmultimap->erase(boostmultimap->begin()++); - stdmultimap->erase(stdmultimap->begin()++); + boostmap->erase(boostmap->begin()); + stdmap->erase(stdmap->begin()); + boostmultimap->erase(boostmultimap->begin()); + stdmultimap->erase(stdmultimap->begin()); if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; @@ -467,9 +467,10 @@ int map_test () delete boostmultimap; delete stdmultimap; } - catch(...){ - throw; + BOOST_CATCH(...){ + BOOST_RETHROW; } + BOOST_CATCH_END return 0; } @@ -485,7 +486,7 @@ int map_test_copyable () const int max = 100; - try{ + BOOST_TRY{ MyBoostMap *boostmap = new MyBoostMap; MyStdMap *stdmap = new MyStdMap; MyBoostMultiMap *boostmultimap = new MyBoostMultiMap; @@ -537,9 +538,10 @@ int map_test_copyable () delete stdmultimap; } } - catch(...){ - throw; + BOOST_CATCH(...){ + BOOST_RETHROW; } + BOOST_CATCH_END return 0; } 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/set_test.hpp b/test/set_test.hpp index 91397c9..a0a56e8 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -143,20 +143,20 @@ int set_test () return 1; } - typename MyBoostSet::iterator it; + typename MyBoostSet::iterator it = boostset->begin(); typename MyBoostSet::const_iterator cit = it; (void)cit; - boostset->erase(boostset->begin()++); - stdset->erase(stdset->begin()++); - boostmultiset->erase(boostmultiset->begin()++); - stdmultiset->erase(stdmultiset->begin()++); + boostset->erase(boostset->begin()); + stdset->erase(stdset->begin()); + boostmultiset->erase(boostmultiset->begin()); + stdmultiset->erase(stdmultiset->begin()); if(!CheckEqualContainers(boostset, stdset)){ - std::cout << "Error in boostset->erase(boostset->begin()++)" << std::endl; + std::cout << "Error in boostset->erase(boostset->begin())" << std::endl; return 1; } if(!CheckEqualContainers(boostmultiset, stdmultiset)){ - std::cout << "Error in boostmultiset->erase(boostmultiset->begin()++)" << std::endl; + std::cout << "Error in boostmultiset->erase(boostmultiset->begin())" << std::endl; return 1; } @@ -443,7 +443,7 @@ int set_test_copyable () typedef typename MyBoostSet::value_type IntType; const int max = 100; - try{ + BOOST_TRY{ //Shared memory allocator must be always be initialized //since it has no default constructor MyBoostSet *boostset = new MyBoostSet; @@ -492,9 +492,10 @@ int set_test_copyable () delete boostset; delete boostmultiset; } - catch(...){ - throw; + BOOST_CATCH(...){ + BOOST_RETHROW; } + BOOST_CATCH_END return 0; } diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 46d6851..808d25c 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -30,6 +30,16 @@ template class boost::container::slist >; + +namespace container_detail { + +template class slist_const_iterator + >::container_type::iterator >; +template class slist_iterator + >::container_type::iterator>; + +} + }} typedef slist MyList; diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index c69efe4..748886e 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -39,6 +39,13 @@ template class stable_vector >; +namespace stable_vector_detail{ + +template class iterator< int, int &, int *>; +template class iterator< int, const int &, const int *>; + +} + }} class recursive_vector diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp new file mode 100644 index 0000000..21efeb7 --- /dev/null +++ b/test/static_vector_test.cpp @@ -0,0 +1,733 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include + +// 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 &){}; // user defined +} // namespace boost +#endif // BOOST_NO_EXCEPTIONS + +#include +#include + +#include +#include + +#include "static_vector_test.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::static_vector; + +}} + + +template +void test_ctor_ndc() +{ + static_vector s; + BOOST_TEST_EQ(s.size() , 0u); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(0u), std::out_of_range ); +} + +template +void test_ctor_nc(size_t n) +{ + static_vector s(n); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + 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); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_resize_nc(size_t n) +{ + static_vector s; + + s.resize(n); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + T val10(10); + s[0] = val10; + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + T val20(20); + s.at(1) = val20; + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_resize_nd(size_t n, T const& v) +{ + static_vector s; + + s.resize(n, v); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_push_back_nd() +{ + static_vector s; + + BOOST_TEST(s.size() == 0); + BOOST_TEST_THROWS( s.at(0), std::out_of_range ); + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + BOOST_TEST(s.size() == i + 1); + BOOST_TEST_THROWS( s.at(i + 1), std::out_of_range ); + BOOST_TEST(T(i) == s.at(i)); + BOOST_TEST(T(i) == s[i]); + BOOST_TEST(T(i) == s.back()); + BOOST_TEST(T(0) == s.front()); + BOOST_TEST(T(i) == *(s.data() + i)); + } +} + +template +void test_pop_back_nd() +{ + static_vector s; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + } + + for ( size_t i = N ; i > 1 ; --i ) + { + s.pop_back(); + BOOST_TEST(s.size() == i - 1); + BOOST_TEST_THROWS( s.at(i - 1), std::out_of_range ); + BOOST_TEST(T(i - 2) == s.at(i - 2)); + BOOST_TEST(T(i - 2) == s[i - 2]); + BOOST_TEST(T(i - 2) == s.back()); + BOOST_TEST(T(0) == s.front()); + } +} + +template +void test_compare_ranges(It1 first1, It1 last1, It2 first2, It2 last2) +{ + BOOST_TEST(std::distance(first1, last1) == std::distance(first2, last2)); + for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2 ) + BOOST_TEST(*first1 == *first2); +} + +template +void test_copy_and_assign(C const& c) +{ + { + static_vector s(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } + { + static_vector s; + BOOST_TEST(0 == s.size()); + s.assign(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } +} + +template +void test_copy_and_assign_nd(T const& val) +{ + static_vector s; + std::vector v; + std::list l; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + v.push_back(t); + l.push_back(t); + } + // copy ctor + { + static_vector s1(s); + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + // copy assignment + { + static_vector s1; + BOOST_TEST(0 == s1.size()); + s1 = s; + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + + // ctor(Iter, Iter) and assign(Iter, Iter) + test_copy_and_assign(s); + test_copy_and_assign(v); + test_copy_and_assign(l); + + // assign(N, V) + { + static_vector s1(s); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + std::vector a(N, val); + s1.assign(N, val); + test_compare_ranges(a.begin(), a.end(), s1.begin(), s1.end()); + } + + stable_vector bsv(s.begin(), s.end()); + vector bv(s.begin(), s.end()); + test_copy_and_assign(bsv); + test_copy_and_assign(bv); +} + +template +void test_iterators_nd() +{ + static_vector s; + std::vector v; + + for ( size_t i = 0 ; i < N ; ++i ) + { + s.push_back(T(i)); + v.push_back(T(i)); + } + + test_compare_ranges(s.begin(), s.end(), v.begin(), v.end()); + test_compare_ranges(s.rbegin(), s.rend(), v.rbegin(), v.rend()); + + s.assign(v.rbegin(), v.rend()); + + test_compare_ranges(s.begin(), s.end(), v.rbegin(), v.rend()); + test_compare_ranges(s.rbegin(), s.rend(), v.begin(), v.end()); +} + +template +void test_erase_nd() +{ + static_vector s; + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < N ; ++i ) + s.push_back(T(i)); + + // erase(pos) + { + for ( size_t i = 0 ; i < N ; ++i ) + { + static_vector s1(s); + It it = s1.erase(s1.begin() + i); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - 1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+1 ; j < N ; ++j ) + BOOST_TEST(s1[j-1] == T(j)); + } + } + // erase(first, last) + { + size_t n = N/3; + for ( size_t i = 0 ; i <= N ; ++i ) + { + static_vector s1(s); + size_t removed = i + n < N ? n : N - i; + It it = s1.erase(s1.begin() + i, s1.begin() + i + removed); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - removed); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+n ; j < N ; ++j ) + BOOST_TEST(s1[j-n] == T(j)); + } + } +} + +template +void test_insert(SV const& s, C const& c) +{ + size_t h = N/2; + size_t n = size_t(h/1.5f); + + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + + typename C::const_iterator it = c.begin(); + std::advance(it, n); + typename static_vector::iterator + it1 = s1.insert(s1.begin() + i, c.begin(), it); + + BOOST_TEST(s1.begin() + i == it1); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == T(100 + j)); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } +} + +template +void test_insert_nd(T const& val) +{ + size_t h = N/2; + + static_vector s, ss; + std::vector v; + std::list l; + + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < h ; ++i ) + { + s.push_back(T(i)); + ss.push_back(T(100 + i)); + v.push_back(T(100 + i)); + l.push_back(T(100 + i)); + } + + // insert(pos, val) + { + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + BOOST_TEST(s1[i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+1] == T(j+i)); + } + } + // insert(pos, n, val) + { + size_t n = size_t(h/1.5f); + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, n, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } + } + // insert(pos, first, last) + test_insert(s, ss); + test_insert(s, v); + test_insert(s, l); + + stable_vector bsv(ss.begin(), ss.end()); + vector bv(ss.begin(), ss.end()); + test_insert(s, bv); + test_insert(s, bsv); +} + +template +void test_capacity_0_nd() +{ + static_vector v(5u, T(0)); + + static_vector s; + BOOST_TEST(s.size() == 0); + BOOST_TEST(s.capacity() == 0); + BOOST_TEST_THROWS(s.at(0), std::out_of_range); + BOOST_TEST_THROWS(s.resize(5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), 5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(5u, T(0)), std::bad_alloc); + typedef static_vector static_vector_0_t; + BOOST_TEST_THROWS(static_vector_0_t s2(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(static_vector_0_t s1(5u, T(0)), std::bad_alloc); +} + +template +void test_exceptions_nd() +{ + static_vector v(N, T(0)); + static_vector s(N/2, T(0)); + + BOOST_TEST_THROWS(s.resize(N, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), N, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(N, T(0)), std::bad_alloc); + typedef static_vector static_vector_n_half_t; + BOOST_TEST_THROWS(static_vector_n_half_t s2(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(static_vector_n_half_t s1(N, T(0)), std::bad_alloc); +} + +template +void test_swap_and_move_nd() +{ + { + static_vector v1, v2, v3, v4; + static_vector s1, s2; + static_vector s4; + + for (size_t i = 0 ; i < N ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + v4.push_back(T(i)); + } + for (size_t i = 0 ; i < N/2 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + s4.push_back(T(100 + i)); + } + + s1.swap(v1); + s2 = boost::move(v2); + static_vector s3(boost::move(v3)); + s4.swap(v4); + + BOOST_TEST(v1.size() == N/2); + BOOST_TEST(s1.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s3.size() == N); + BOOST_TEST(v4.size() == N/2); + BOOST_TEST(s4.size() == N); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(v1[i] == T(100 + i)); + BOOST_TEST(v4[i] == T(100 + i)); + } + for (size_t i = 0 ; i < N ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + BOOST_TEST(s4[i] == T(i)); + } + } + { + static_vector v1, v2, v3; + static_vector s1, s2; + + for (size_t i = 0 ; i < N/2 ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + } + for (size_t i = 0 ; i < N/3 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + } + + s1.swap(v1); + s2 = boost::move(v2); + static_vector s3(boost::move(v3)); + + BOOST_TEST(v1.size() == N/3); + BOOST_TEST(s1.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s3.size() == N/2); + for (size_t i = 0 ; i < N/3 ; ++i ) + BOOST_TEST(v1[i] == T(100 + i)); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + } + } + { + typedef static_vector small_vector_t; + static_vector v(N, T(0)); + small_vector_t s(N/2, T(1)); + BOOST_TEST_THROWS(s.swap(v), std::bad_alloc); + v.resize(N, T(0)); + BOOST_TEST_THROWS(s = boost::move(v), std::bad_alloc); + v.resize(N, T(0)); + BOOST_TEST_THROWS(small_vector_t s2(boost::move(v)), std::bad_alloc); + } +} + +template +void test_emplace_0p() +{ + //emplace_back() + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(); + BOOST_TEST(v.size() == N); + BOOST_TEST_THROWS(v.emplace_back(), std::bad_alloc); + } +} + +template +void test_emplace_2p() +{ + //emplace_back(pos, int, int) + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(i, 100 + i); + BOOST_TEST(v.size() == N); + BOOST_TEST_THROWS(v.emplace_back(N, 100 + N), std::bad_alloc); + BOOST_TEST(v.size() == N); + for (int i = 0 ; i < int(N) ; ++i ) + BOOST_TEST(v[i] == T(i, 100 + i)); + } + + // emplace(pos, int, int) + { + typedef typename static_vector::iterator It; + + int h = N / 2; + + static_vector v; + for ( int i = 0 ; i < h ; ++i ) + v.emplace_back(i, 100 + i); + + for ( int i = 0 ; i <= h ; ++i ) + { + static_vector vv(v); + It it = vv.emplace(vv.begin() + i, i+100, i+200); + BOOST_TEST(vv.begin() + i == it); + BOOST_TEST(vv.size() == size_t(h+1)); + for ( int j = 0 ; j < i ; ++j ) + BOOST_TEST(vv[j] == T(j, j+100)); + BOOST_TEST(vv[i] == T(i+100, i+200)); + for ( int j = 0 ; j < h-i ; ++j ) + BOOST_TEST(vv[j+i+1] == T(j+i, j+i+100)); + } + } +} + +template +void test_sv_elem(T const& t) +{ + typedef static_vector V; + + static_vector v; + + v.push_back(V(N/2, t)); + V vvv(N/2, t); + v.push_back(boost::move(vvv)); + v.insert(v.begin(), V(N/2, t)); + v.insert(v.end(), V(N/2, t)); + v.emplace_back(N/2, t); +} + +int main(int, char* []) +{ + 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_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_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_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_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_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_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_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_exceptions_nd(); + test_exceptions_nd(); + test_exceptions_nd(); + BOOST_TEST(counting_value::count() == 0); + test_exceptions_nd(); + test_exceptions_nd(); + + test_swap_and_move_nd(); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + BOOST_TEST(counting_value::count() == 0); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + + test_emplace_0p(); + BOOST_TEST(counting_value::count() == 0); + + test_emplace_2p(); + BOOST_TEST(counting_value::count() == 0); + + test_sv_elem(50); + test_sv_elem(value_nd(50)); + test_sv_elem(counting_value(50)); + BOOST_TEST(counting_value::count() == 0); + test_sv_elem(shptr_value(50)); + test_sv_elem(movable_and_copyable_int(50)); + return boost::report_errors(); +} + +#include diff --git a/test/static_vector_test.hpp b/test/static_vector_test.hpp new file mode 100644 index 0000000..f2b3a65 --- /dev/null +++ b/test/static_vector_test.hpp @@ -0,0 +1,99 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP +#define BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP + +#include + +#include +#include "movable_int.hpp" + +using namespace boost::container; + +class value_ndc +{ +public: + explicit value_ndc(int a) : aa(a) {} + ~value_ndc() {} + bool operator==(value_ndc const& v) const { return aa == v.aa; } + bool operator<(value_ndc const& v) const { return aa < v.aa; } +private: + value_ndc(value_ndc const&) {} + value_ndc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class value_nd +{ +public: + explicit value_nd(int a) : aa(a) {} + ~value_nd() {} + bool operator==(value_nd const& v) const { return aa == v.aa; } + bool operator<(value_nd const& v) const { return aa < v.aa; } +private: + int aa; +}; + +class value_nc +{ +public: + explicit value_nc(int a = 0) : aa(a) {} + ~value_nc() {} + bool operator==(value_nc const& v) const { return aa == v.aa; } + bool operator<(value_nc const& v) const { return aa < v.aa; } +private: + value_nc(value_nc const&) {} + value_nc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class counting_value +{ + BOOST_COPYABLE_AND_MOVABLE(counting_value) + +public: + explicit counting_value(int a = 0, int b = 0) : aa(a), bb(b) { ++c(); } + counting_value(counting_value const& v) : aa(v.aa), bb(v.bb) { ++c(); } + counting_value(BOOST_RV_REF(counting_value) p) : aa(p.aa), bb(p.bb) { p.aa = 0; p.bb = 0; ++c(); } // Move constructor + counting_value& operator=(BOOST_RV_REF(counting_value) p) { aa = p.aa; p.aa = 0; bb = p.bb; p.bb = 0; return *this; } // Move assignment + counting_value& operator=(BOOST_COPY_ASSIGN_REF(counting_value) p) { aa = p.aa; bb = p.bb; return *this; } // Copy assignment + ~counting_value() { --c(); } + bool operator==(counting_value const& v) const { return aa == v.aa && bb == v.bb; } + bool operator<(counting_value const& v) const { return aa < v.aa || ( aa == v.aa && bb < v.bb ); } + static size_t count() { return c(); } + +private: + static size_t & c() { static size_t co = 0; return co; } + int aa, bb; +}; + +namespace boost { + +template <> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} + +class shptr_value +{ + typedef boost::shared_ptr Ptr; +public: + explicit shptr_value(int a = 0) : m_ptr(new int(a)) {} + bool operator==(shptr_value const& v) const { return *m_ptr == *(v.m_ptr); } + bool operator<(shptr_value const& v) const { return *m_ptr < *(v.m_ptr); } +private: + boost::shared_ptr m_ptr; +}; + +#endif // BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP diff --git a/test/throw_exception_test.cpp b/test/throw_exception_test.cpp new file mode 100644 index 0000000..2572dfe --- /dev/null +++ b/test/throw_exception_test.cpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS + +#include + +#include +#include + +using namespace boost::container; + +static bool bad_alloc_called = false; +static bool out_of_range_called = false; +static bool length_error_called = false; +static bool logic_error_called = false; +static bool runtime_error_called = false; + +//User defined throw implementations +namespace boost { +namespace container { + + void throw_bad_alloc() + { bad_alloc_called = true; } + + void throw_out_of_range(const char* str) + { (void)str; out_of_range_called = true; } + + void throw_length_error(const char* str) + { (void)str; length_error_called = true; } + + void throw_logic_error(const char* str) + { (void)str; logic_error_called = true; } + + void throw_runtime_error(const char* str) + { (void)str; runtime_error_called = true; } + +}} //boost::container + +int main() +{ + //Check user-defined throw callbacks are called + throw_bad_alloc(); + BOOST_TEST(bad_alloc_called == true); + throw_out_of_range("dummy"); + BOOST_TEST(out_of_range_called == true); + throw_length_error("dummy"); + BOOST_TEST(length_error_called == true); + throw_logic_error("dummy"); + BOOST_TEST(logic_error_called == true); + throw_runtime_error("dummy"); + BOOST_TEST(runtime_error_called == true); + return ::boost::report_errors(); +} + +#include diff --git a/test/vector_test.cpp b/test/vector_test.cpp index a872315..5ea8a05 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -39,6 +39,17 @@ template class boost::container::vector >; +namespace container_detail { + +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template class vector_const_iterator; +template class vector_iterator; + +#endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +} + }} int test_expand_bwd() diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 503ec59..b1a4fb5 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -30,6 +30,8 @@ #include "input_from_forward_iterator.hpp" #include #include +#include +#include "insert_test.hpp" namespace boost{ namespace container { @@ -79,6 +81,17 @@ bool vector_copyable_only(V1 *boostvector, V2 *stdvector, boost::container::cont stdvector->push_back(int(3)); if(!test::CheckEqualContainers(boostvector, stdvector)) return false; } + { + V1 *pv1 = new V1(*boostvector); + V2 *pv2 = new V2(*stdvector); + boostvector->clear(); + stdvector->clear(); + boostvector->assign(pv1->begin(), pv1->end()); + stdvector->assign(pv2->begin(), pv2->end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + delete pv1; + delete pv2; + } return true; } @@ -90,8 +103,12 @@ int vector_test() typedef typename MyBoostVector::value_type IntType; const int max = 100; + if(!test_range_insertion()){ + return 1; + } + { - try{ + BOOST_TRY{ MyBoostVector *boostvector = new MyBoostVector; MyStdVector *stdvector = new MyStdVector; boostvector->resize(100); @@ -160,38 +177,38 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-2); + IntType new_int(-i); aux_vect[i] = boost::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -2; + aux_vect2[i] = -i; } typename MyBoostVector::size_type old_size = boostvector->size(); typename MyBoostVector::iterator insert_it = - boostvector->insert(boostvector->begin() + old_size + boostvector->insert(boostvector->begin() + old_size/2 ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(aux_vect + 50)); - if(boostvector->begin() + old_size != insert_it) return 1; - stdvector->insert(stdvector->begin() + old_size, aux_vect2, aux_vect2 + 50); + if(boostvector->begin() + old_size/2 != insert_it) return 1; + stdvector->insert(stdvector->begin() + old_size/2, aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; for(int i = 0; i < 50; ++i){ - IntType new_int(-3); + IntType new_int(-i); aux_vect[i] = boost::move(new_int); } for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -3; + aux_vect2[i] = -i; } old_size = boostvector->size(); //Now try with input iterators instead - insert_it = boostvector->insert(boostvector->begin() + old_size + insert_it = boostvector->insert(boostvector->begin() + old_size/2 ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) ,boost::make_move_iterator(make_input_from_forward_iterator(aux_vect + 50)) ); - if(boostvector->begin() + old_size != insert_it) return 1; - stdvector->insert(stdvector->begin() + old_size, aux_vect2, aux_vect2 + 50); + if(boostvector->begin() + old_size/2 != insert_it) return 1; + stdvector->insert(stdvector->begin() + old_size/2, aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } /* //deque has no reserve @@ -215,7 +232,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(); @@ -292,11 +314,15 @@ int vector_test() delete stdvector; delete boostvector; } - catch(std::exception &ex){ + BOOST_CATCH(std::exception &ex){ + #ifndef BOOST_NO_EXCEPTIONS std::cout << ex.what() << std::endl; + #endif return 1; } + BOOST_CATCH_END } + std::cout << std::endl << "Test OK!" << std::endl; return 0; } @@ -308,4 +334,3 @@ int vector_test() #include #endif //BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER -