Additional vector speed improvements, added basic benchmark against varray

[SVN r83126]
This commit is contained in:
Ion Gaztañaga
2013-02-24 13:13:36 +00:00
parent b3d5f6480b
commit 0896d04ddf
19 changed files with 5296 additions and 924 deletions

34
bench/Jamfile.v2 Normal file
View File

@@ -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 ] ;

View File

@@ -0,0 +1,147 @@
// benchmark based on: http://cpp-next.com/archive/2010/10/howards-stl-move-semantics-benchmark/
//
// @file bench_static_vector.cpp
// @date Aug 14, 2011
// @author Andrew Hundt <ATHundt@gmail.com>
//
// (C) 2011-2012 Andrew Hundt <ATHundt@gmail.com>
// (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 <vector>
#include <iostream>
#include <boost/timer/timer.hpp>
#include <set>
#include <algorithm>
#include <exception>
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<typename T>
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<typename T>
T &generate()
{
T &v = *new T;
v.reserve(N);
for (std::size_t i = 0; i < N; ++i){
typename T::reference r = get_set<typename T::value_type>(i);
v.push_back(boost::move(r));
delete &r;
}
return v;
}
template<typename T>
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<T>();
constructTime.stop();
sortTime.resume();
std::sort(v.begin(), v.end());
sortTime.stop();
rotateTime.resume();
std::rotate(v.begin(), v.begin() + v.size()/2, v.end());
rotateTime.stop();
destructionTime.resume();
delete &v;
}
destructionTime.stop();
}
totalTime.stop();
std::cout << " construction took " << boost::timer::format(constructTime.elapsed());
std::cout << " sort took " << boost::timer::format(sortTime.elapsed());
std::cout << " rotate took " << boost::timer::format(rotateTime.elapsed());
std::cout << " destruction took " << boost::timer::format(destructionTime.elapsed());
std::cout << " Total time = " << boost::timer::format(totalTime.elapsed()) << std::endl;
return totalTime.elapsed();
}
void compare_times(cpu_times time_numerator, cpu_times time_denominator){
std::cout
<< "\n wall = " << ((double)time_numerator.wall/(double)time_denominator.wall)
<< "\n user = " << ((double)time_numerator.user/(double)time_denominator.user)
<< "\n system = " << ((double)time_numerator.system/(double)time_denominator.system)
<< "\n (user+system) = " << ((double)(time_numerator.system+time_numerator.user)/(double)(time_denominator.system+time_denominator.user)) << "\n\n";
}
int main()
{
try {
std::cout << "N = " << N << "\n\n";
std::cout << "varray benchmark:\n";
cpu_times time_varray = time_it<boost::container::varray<boost::container::varray<basic_type_t,N>,N > >();
std::cout << "boost::container::static_vector benchmark\n";
cpu_times time_boost_static_vector = time_it<boost::container::static_vector<boost::container::static_vector<basic_type_t,N>,N > >();
std::cout << "boost::container::vector benchmark\n";
cpu_times time_boost_vector = time_it<boost::container::vector<boost::container::vector<basic_type_t> > >();
std::cout << "std::vector benchmark\n";
cpu_times time_standard_vector = time_it<std::vector<std::vector<basic_type_t> > >();
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;
}

2274
bench/detail/varray.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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 <boost/concept_check.hpp>
namespace boost { namespace container { namespace container_detail { namespace concept {
/**
* VArrayStrategyConcept
*
* \brief Checks strategy for varray<Value,Capacity,Strategy>, which has similarities to std::Allocator
* \ingroup varray
*/
template<typename Strategy>
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

View File

@@ -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 <cstddef>
#include <cstring>
#include <memory>
#include <limits>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/int.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/has_trivial_assign.hpp>
#include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
//#include <boost/type_traits/has_nothrow_constructor.hpp>
//#include <boost/type_traits/has_nothrow_copy.hpp>
//#include <boost/type_traits/has_nothrow_assign.hpp>
//#include <boost/type_traits/has_nothrow_destructor.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/iterator/iterator_traits.hpp>
// 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 <vector>
#include <boost/container/vector.hpp>
#endif // BOOST_CONTAINER_VARRAY_ENABLE_ITERATORS_OPTIMIZATION && !BOOST_NO_EXCEPTIONS
namespace boost { namespace container { namespace varray_detail {
template <typename I>
struct are_elements_contiguous : boost::is_pointer<I>
{};
#if defined(BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS)
template <typename Pointer>
struct are_elements_contiguous<
boost::container::container_detail::vector_const_iterator<Pointer>
> : boost::true_type
{};
template <typename Pointer>
struct are_elements_contiguous<
boost::container::container_detail::vector_iterator<Pointer>
> : boost::true_type
{};
#if defined(BOOST_DINKUMWARE_STDLIB)
template <typename T>
struct are_elements_contiguous<
std::_Vector_const_iterator<T>
> : boost::true_type
{};
template <typename T>
struct are_elements_contiguous<
std::_Vector_iterator<T>
> : boost::true_type
{};
#elif defined(BOOST_GNU_STDLIB)
template <typename P, typename T, typename A>
struct are_elements_contiguous<
__gnu_cxx::__normal_iterator<P, std::vector<T, A> >
> : boost::true_type
{};
#elif defined(_LIBCPP_VERSION)
// TODO - test it first
//template <typename P>
//struct are_elements_contiguous<
// __wrap_iter<P>
//> : 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 <typename I, typename O>
struct are_corresponding :
::boost::mpl::and_<
::boost::is_same<
::boost::remove_const<
typename ::boost::iterator_value<I>::type
>,
::boost::remove_const<
typename ::boost::iterator_value<O>::type
>
>,
are_elements_contiguous<I>,
are_elements_contiguous<O>
>
{};
template <typename I, typename V>
struct is_corresponding_value :
::boost::is_same<
::boost::remove_const<
typename ::boost::iterator_value<I>::type
>,
::boost::remove_const<V>
>
{};
// destroy(I, I)
template <typename I>
void destroy_dispatch(I /*first*/, I /*last*/,
boost::true_type const& /*has_trivial_destructor*/)
{}
template <typename I>
void destroy_dispatch(I first, I last,
boost::false_type const& /*has_trivial_destructor*/)
{
typedef typename boost::iterator_value<I>::type value_type;
for ( ; first != last ; ++first )
first->~value_type();
}
template <typename I>
void destroy(I first, I last)
{
typedef typename boost::iterator_value<I>::type value_type;
destroy_dispatch(first, last, has_trivial_destructor<value_type>());
}
// destroy(I)
template <typename I>
void destroy_dispatch(I /*pos*/,
boost::true_type const& /*has_trivial_destructor*/)
{}
template <typename I>
void destroy_dispatch(I pos,
boost::false_type const& /*has_trivial_destructor*/)
{
typedef typename boost::iterator_value<I>::type value_type;
pos->~value_type();
}
template <typename I>
void destroy(I pos)
{
typedef typename boost::iterator_value<I>::type value_type;
destroy_dispatch(pos, has_trivial_destructor<value_type>());
}
// copy(I, I, O)
template <typename I, typename O>
inline O copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline O copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return std::copy(first, last, dst); // may throw
}
template <typename I, typename O>
inline O copy(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<O>::type
>
>::type
use_memmove;
return copy_dispatch(first, last, dst, use_memmove()); // may throw
}
// uninitialized_copy(I, I, O)
template <typename I, typename O>
inline
O uninitialized_copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename F>
inline
F uninitialized_copy_dispatch(I first, I last, F dst,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
return std::uninitialized_copy(first, last, dst); // may throw
}
template <typename I, typename F>
inline
F uninitialized_copy(I first, I last, F dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, F>,
::boost::has_trivial_copy<
typename ::boost::iterator_value<F>::type
>
>::type
use_memcpy;
return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw
}
// uninitialized_move(I, I, O)
template <typename I, typename O>
inline
O uninitialized_move_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline
O uninitialized_move_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
//return boost::uninitialized_move(first, last, dst); // may throw
O o = dst;
BOOST_TRY
{
typedef typename std::iterator_traits<O>::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 <typename I, typename O>
inline
O uninitialized_move(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_copy<
typename ::boost::iterator_value<O>::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 <typename I, typename O>
inline
O move_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline
O move_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return boost::move(first, last, dst); // may throw
}
template <typename I, typename O>
inline
O move(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<O>::type
>
>::type
use_memmove;
return move_dispatch(first, last, dst, use_memmove()); // may throw
}
// move_backward(BDI, BDI, BDO)
template <typename BDI, typename BDO>
inline
BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<BDI>::type value_type;
typename boost::iterator_difference<BDI>::type d = std::distance(first, last);
BDO foo(dst - d);
::memmove(boost::addressof(*foo), boost::addressof(*first), sizeof(value_type) * d);
return foo;
}
template <typename BDI, typename BDO>
inline
BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return boost::move_backward(first, last, dst); // may throw
}
template <typename BDI, typename BDO>
inline
BDO move_backward(BDI first, BDI last, BDO dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<BDI, BDO>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<BDO>::type
>
>::type
use_memmove;
return move_backward_dispatch(first, last, dst, use_memmove()); // may throw
}
template <typename T>
struct has_nothrow_move : public
::boost::mpl::or_<
boost::mpl::bool_<
::boost::has_nothrow_move<
typename ::boost::remove_const<T>::type
>::value
>,
boost::mpl::bool_<
::boost::has_nothrow_move<T>::value
>
>
{};
// uninitialized_move_if_noexcept(I, I, O)
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
{ return uninitialized_move(first, last, dst); }
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
{ return uninitialized_copy(first, last, dst); }
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept(I first, I last, O dst)
{
typedef typename has_nothrow_move<
typename ::boost::iterator_value<O>::type
>::type use_move;
return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
}
// move_if_noexcept(I, I, O)
template <typename I, typename O>
inline
O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
{ return move(first, last, dst); }
template <typename I, typename O>
inline
O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
{ return copy(first, last, dst); }
template <typename I, typename O>
inline
O move_if_noexcept(I first, I last, O dst)
{
typedef typename has_nothrow_move<
typename ::boost::iterator_value<O>::type
>::type use_move;
return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
}
// uninitialized_fill(I, I)
template <typename I>
inline
void uninitialized_fill_dispatch(I first, I last,
boost::true_type const& /*has_trivial_constructor*/,
boost::true_type const& /*disable_trivial_init*/)
{}
template <typename I>
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<I>::type value_type;
for ( ; first != last ; ++first )
new (boost::addressof(*first)) value_type();
}
template <typename I, typename DisableTrivialInit>
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<I>::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 <typename I, typename DisableTrivialInit>
inline
void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init)
{
typedef typename boost::iterator_value<I>::type value_type;
uninitialized_fill_dispatch(first, last, boost::has_trivial_constructor<value_type>(), disable_trivial_init); // may throw
}
// construct(I)
template <typename I>
inline
void construct_dispatch(boost::mpl::bool_<true> const& /*dont_init*/, I pos)
{}
template <typename I>
inline
void construct_dispatch(boost::mpl::bool_<false> const& /*dont_init*/, I pos)
{
typedef typename ::boost::iterator_value<I>::type value_type;
new (static_cast<void*>(::boost::addressof(*pos))) value_type(); // may throw
}
template <typename DisableTrivialInit, typename I>
inline
void construct(DisableTrivialInit const&, I pos)
{
typedef typename ::boost::iterator_value<I>::type value_type;
typedef typename ::boost::mpl::and_<
boost::has_trivial_constructor<value_type>,
DisableTrivialInit
>::type dont_init;
construct_dispatch(dont_init(), pos); // may throw
}
// construct(I, V)
template <typename I, typename V>
inline
void construct_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename P>
inline
void construct_dispatch(I pos, P const& p,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(boost::addressof(*pos))) V(p); // may throw
}
template <typename DisableTrivialInit, typename I, typename P>
inline
void construct(DisableTrivialInit const&,
I pos, P const& p)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, P>,
::boost::has_trivial_copy<P>
>::type
use_memcpy;
construct_dispatch(pos, p, use_memcpy()); // may throw
}
// Needed by push_back(V &&)
template <typename DisableTrivialInit, typename I, typename P>
inline
void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, P>,
::boost::has_trivial_copy<P>
>::type
use_memcpy;
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(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 <typename DisableTrivialInit, typename I, class ...Args>
inline
void construct(DisableTrivialInit const&,
I pos,
BOOST_FWD_REF(Args) ...args)
{
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(boost::addressof(*pos))) V(::boost::forward<Args>(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 <typename DisableTrivialInit, typename I, typename P BOOST_PP_ENUM_TRAILING_PARAMS(n, typename P) > \
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<I>::type V; \
new \
(static_cast<void*>(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 <typename I, typename V>
inline
void assign_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename V>
inline
void assign_dispatch(I pos, V const& v,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
*pos = v; // may throw
}
template <typename I, typename V>
inline
void assign(I pos, V const& v)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, V>,
::boost::has_trivial_assign<V>
>::type
use_memcpy;
assign_dispatch(pos, v, use_memcpy()); // may throw
}
template <typename I, typename V>
inline
void assign(I pos, BOOST_RV_REF(V) v)
{
*pos = boost::move(v); // may throw
}
// uninitialized_copy_s
template <typename I, typename F>
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<std::size_t>::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 T>
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

994
bench/varray.hpp Normal file
View File

@@ -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 <boost/container/detail/config_begin.hpp>
#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 <typename Value, std::size_t Capacity>
class varray
: public container_detail::varray<Value, Capacity>
{
typedef container_detail::varray<Value, Capacity> 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 <tt>count <= capacity()</tt>
//!
//! @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 <tt>count <= capacity()</tt>
//!
//! @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 <tt>distance(first, last) <= capacity()</tt>
//! @li Iterator must meet the \c ForwardTraversalIterator concept.
//!
//! @brief Constructs a varray containing copy of a range <tt>[first, last)</tt>.
//!
//! @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 <typename Iterator>
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 <tt>other.size() <= capacity()</tt>.
//!
//! @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 <std::size_t C>
varray(varray<value_type, C> 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<base_t const&>(other));
return *this;
}
//! @pre <tt>other.size() <= capacity()</tt>
//!
//! @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 <std::size_t C>
// TEMPORARY WORKAROUND
#if defined(BOOST_NO_RVALUE_REFERENCES)
varray & operator=(::boost::rv< varray<value_type, C> > const& other)
#else
varray & operator=(varray<value_type, C> const& other)
#endif
{
base_t::operator=(static_cast<varray<value_type, C> 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>::value is \c true and Value's move constructor throws.
//! @li If \c boost::has_nothrow_move<Value>::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<base_t&>(other)))
{}
//! @pre <tt>other.size() <= capacity()</tt>
//!
//! @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>::value is \c true and Value's move constructor throws.
//! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
varray(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other)
: base_t(boost::move(static_cast<container_detail::varray<value_type, C>&>(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>::value is \c true and Value's move constructor or move assignment throws.
//! @li If \c boost::has_nothrow_move<Value>::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<base_t&>(other)));
return *this;
}
//! @pre <tt>other.size() <= capacity()</tt>
//!
//! @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>::value is \c true and Value's move constructor or move assignment throws.
//! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
varray & operator=(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other)
{
base_t::operator=(boost::move(static_cast<container_detail::varray<value_type, C>&>(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>::value is \c true and Value's move constructor or move assignment throws,
//! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
void swap(varray & other);
//! @pre <tt>other.size() <= capacity() && size() <= other.capacity()</tt>
//!
//! @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>::value is \c true and Value's move constructor or move assignment throws,
//! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
void swap(varray<value_type, C> & other);
//! @pre <tt>count <= capacity()</tt>
//!
//! @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 <tt>count <= capacity()</tt>
//!
//! @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 <tt>count <= capacity()</tt>
//!
//! @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 <tt>size() < capacity()</tt>
//!
//! @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 <tt>size() < capacity()</tt>
//!
//! @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 <tt>!empty()</tt>
//!
//! @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 <tt>[begin(), end()]</tt>.
//! @li <tt>size() < capacity()</tt>
//!
//! @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 <tt>[begin(), end()]</tt>.
//! @li <tt>size() < capacity()</tt>
//!
//! @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 <tt>[begin(), end()]</tt>.
//! @li <tt>size() + count <= capacity()</tt>
//!
//! @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 <tt>[begin(), end()]</tt>.
//! @li <tt>distance(first, last) <= capacity()</tt>
//! @li \c Iterator must meet the \c ForwardTraversalIterator concept.
//!
//! @brief Inserts a copy of a range <tt>[first, last)</tt> 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 <typename Iterator>
iterator insert(iterator position, Iterator first, Iterator last);
//! @pre \c position must be a valid iterator of \c *this in range <tt>[begin(), end())</tt>
//!
//! @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 <tt>[begin(), end()]</tt>
//!
//! @brief Erases Values from a range <tt>[first, last)</tt>.
//!
//! @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 <tt>distance(first, last) <= capacity()</tt>
//!
//! @brief Assigns a range <tt>[first, last)</tt> 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 <typename Iterator>
void assign(Iterator first, Iterator last);
//! @pre <tt>count <= capacity()</tt>
//!
//! @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 <tt>size() < capacity()</tt>
//!
//! @brief Inserts a Value constructed with
//! \c std::forward<Args>(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<class ...Args>
void emplace_back(Args &&...args);
//! @pre
//! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>
//! @li <tt>size() < capacity()</tt>
//!
//! @brief Inserts a Value constructed with
//! \c std::forward<Args>(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<class ...Args>
iterator emplace(iterator position, Args &&...args);
//! @brief Removes all elements from the container.
//!
//! @par Throws
//! Nothing.
//!
//! @par Complexity
//! Constant O(1).
void clear();
//! @pre <tt>i < size()</tt>
//!
//! @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 <tt>i < size()</tt>
//!
//! @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 <tt>i < size()</tt>
//!
//! @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 <tt>i < size()</tt>
//!
//! @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 <tt>[data(), data() + size())</tt> is a valid range.
//! For a non-empty vector <tt>data() == &front()</tt>.
//!
//! @par Throws
//! Nothing.
//!
//! @par Complexity
//! Constant O(1).
Value * data();
//! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range.
//! For a non-empty vector <tt>data() == &front()</tt>.
//!
//! @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<typename V, std::size_t C1, std::size_t C2>
bool operator== (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
bool operator!= (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
bool operator< (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
bool operator> (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
bool operator<= (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
bool operator>= (varray<V, C1> const& x, varray<V, C2> 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<typename V, std::size_t C1, std::size_t C2>
inline void swap(varray<V, C1> & x, varray<V, C2> & y);
#endif // BOOST_CONTAINER_DOXYGEN_INVOKED
}} // namespace boost::container
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_VARRAY_HPP

View File

@@ -663,7 +663,8 @@ use [*Boost.Container]? There are several reasons for that:
* Support for `BOOST_NO_EXCEPTIONS` [@https://svn.boost.org/trac/boost/ticket/7227 #7227]. * 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], * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7921 #7921],
[@https://svn.boost.org/trac/boost/ticket/7969 #7969]. [@https://svn.boost.org/trac/boost/ticket/7969 #7969],
[@https://svn.boost.org/trac/boost/ticket/8118 #8118].
[endsect] [endsect]

View File

@@ -250,7 +250,19 @@ struct allocator_traits
//! <b>Returns</b>: `a.select_on_container_copy_construction()` if that expression is well-formed; //! <b>Returns</b>: `a.select_on_container_copy_construction()` if that expression is well-formed;
//! otherwise, a. //! otherwise, a.
static Alloc select_on_container_copy_construction(const Alloc &a) static
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
typename container_detail::if_c
< boost::container::container_detail::
has_member_function_callable_with_select_on_container_copy_construction
<const Alloc>::value
, Alloc
, const Alloc &
>::type
#else
Alloc
#endif
select_on_container_copy_construction(const Alloc &a)
{ {
const bool value = boost::container::container_detail:: const bool value = boost::container::container_detail::
has_member_function_callable_with_select_on_container_copy_construction has_member_function_callable_with_select_on_container_copy_construction
@@ -295,7 +307,7 @@ struct allocator_traits
static Alloc priv_select_on_container_copy_construction(boost::true_type, const Alloc &a) static Alloc priv_select_on_container_copy_construction(boost::true_type, const Alloc &a)
{ return a.select_on_container_copy_construction(); } { return a.select_on_container_copy_construction(); }
static Alloc priv_select_on_container_copy_construction(boost::false_type, const Alloc &a) static const Alloc &priv_select_on_container_copy_construction(boost::false_type, const Alloc &a)
{ return a; } { return a; }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)

View File

@@ -89,10 +89,10 @@ struct insert_n_copies_proxy
: a_(a), v_(v) : a_(a), v_(v)
{} {}
void uninitialized_copy_n_and_update(Iterator p, size_type n) void uninitialized_copy_n_and_update(Iterator p, size_type n) const
{ boost::container::uninitialized_fill_alloc_n(this->a_, v_, n, p); } { boost::container::uninitialized_fill_alloc_n(this->a_, v_, n, p); }
void copy_n_and_update(Iterator p, size_type n) void copy_n_and_update(Iterator p, size_type n) const
{ std::fill_n(p, n, v_); } { std::fill_n(p, n, v_); }
A &a_; A &a_;
@@ -111,10 +111,10 @@ struct insert_default_constructed_n_proxy
: a_(a) : a_(a)
{} {}
void uninitialized_copy_n_and_update(Iterator p, size_type n) void uninitialized_copy_n_and_update(Iterator p, size_type n) const
{ boost::container::uninitialized_default_alloc_n(this->a_, n, p); } { boost::container::uninitialized_default_alloc_n(this->a_, n, p); }
void copy_n_and_update(Iterator, size_type) void copy_n_and_update(Iterator, size_type) const
{ {
BOOST_ASSERT(false); BOOST_ASSERT(false);
} }
@@ -134,7 +134,7 @@ struct insert_copy_proxy
: a_(a), v_(v) : a_(a), v_(v)
{} {}
void uninitialized_copy_n_and_update(Iterator p, size_type n) void uninitialized_copy_n_and_update(Iterator p, size_type n) const
{ {
BOOST_ASSERT(n == 1); (void)n; BOOST_ASSERT(n == 1); (void)n;
alloc_traits::construct( this->a_ alloc_traits::construct( this->a_
@@ -143,7 +143,7 @@ struct insert_copy_proxy
); );
} }
void copy_n_and_update(Iterator p, size_type n) void copy_n_and_update(Iterator p, size_type n) const
{ {
BOOST_ASSERT(n == 1); (void)n; BOOST_ASSERT(n == 1); (void)n;
*p =v_; *p =v_;
@@ -165,7 +165,7 @@ struct insert_move_proxy
: a_(a), v_(v) : a_(a), v_(v)
{} {}
void uninitialized_copy_n_and_update(Iterator p, size_type n) void uninitialized_copy_n_and_update(Iterator p, size_type n) const
{ {
BOOST_ASSERT(n == 1); (void)n; BOOST_ASSERT(n == 1); (void)n;
alloc_traits::construct( this->a_ alloc_traits::construct( this->a_
@@ -174,7 +174,7 @@ struct insert_move_proxy
); );
} }
void copy_n_and_update(Iterator p, size_type n) void copy_n_and_update(Iterator p, size_type n) const
{ {
BOOST_ASSERT(n == 1); (void)n; BOOST_ASSERT(n == 1); (void)n;
*p = ::boost::move(v_); *p = ::boost::move(v_);

View File

@@ -57,20 +57,29 @@ class static_storage_allocator
public: public:
typedef T value_type; typedef T value_type;
T* internal_storage() const static_storage_allocator() BOOST_CONTAINER_NOEXCEPT
{}
static_storage_allocator(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT
{}
static_storage_allocator & operator=(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT
{}
T* internal_storage() const BOOST_CONTAINER_NOEXCEPT
{ return const_cast<T*>(static_cast<const T*>(static_cast<const void*>(&storage))); } { return const_cast<T*>(static_cast<const T*>(static_cast<const void*>(&storage))); }
T* internal_storage() T* internal_storage() BOOST_CONTAINER_NOEXCEPT
{ return static_cast<T*>(static_cast<void*>(&storage)); } { return static_cast<T*>(static_cast<void*>(&storage)); }
static const std::size_t internal_capacity = N; static const std::size_t internal_capacity = N;
typedef boost::container::container_detail::version_type<static_storage_allocator, 0> version; typedef boost::container::container_detail::version_type<static_storage_allocator, 0> version;
friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT
{ return false; } { return false; }
friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT
{ return true; } { return true; }
private: private:
@@ -123,7 +132,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
static_vector() static_vector() BOOST_CONTAINER_NOEXCEPT
: base_t() : base_t()
{} {}
@@ -386,7 +395,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Linear O(N). //! Linear O(N).
void reserve(size_type count); void reserve(size_type count) BOOST_CONTAINER_NOEXCEPT;
//! @pre <tt>size() < capacity()</tt> //! @pre <tt>size() < capacity()</tt>
//! //!
@@ -594,7 +603,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
void clear(); void clear() BOOST_CONTAINER_NOEXCEPT;
//! @pre <tt>i < size()</tt> //! @pre <tt>i < size()</tt>
//! //!
@@ -724,7 +733,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
Value * data(); Value * data() BOOST_CONTAINER_NOEXCEPT;
//! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range. //! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range.
//! For a non-empty vector <tt>data() == &front()</tt>. //! For a non-empty vector <tt>data() == &front()</tt>.
@@ -734,7 +743,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const Value * data() const; const Value * data() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns iterator to the first element. //! @brief Returns iterator to the first element.
//! //!
@@ -745,7 +754,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
iterator begin(); iterator begin() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const iterator to the first element. //! @brief Returns const iterator to the first element.
//! //!
@@ -756,7 +765,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_iterator begin() const; const_iterator begin() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const iterator to the first element. //! @brief Returns const iterator to the first element.
//! //!
@@ -767,7 +776,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_iterator cbegin() const; const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns iterator to the one after the last element. //! @brief Returns iterator to the one after the last element.
//! //!
@@ -778,7 +787,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
iterator end(); iterator end() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const iterator to the one after the last element. //! @brief Returns const iterator to the one after the last element.
//! //!
@@ -789,7 +798,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_iterator end() const; const_iterator end() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const iterator to the one after the last element. //! @brief Returns const iterator to the one after the last element.
//! //!
@@ -800,7 +809,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_iterator cend() const; const_iterator cend() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns reverse iterator to the first element of the reversed container. //! @brief Returns reverse iterator to the first element of the reversed container.
//! //!
@@ -812,7 +821,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
reverse_iterator rbegin(); reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const reverse iterator to the first element of the reversed container. //! @brief Returns const reverse iterator to the first element of the reversed container.
//! //!
@@ -824,7 +833,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_reverse_iterator rbegin() const; const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const reverse iterator to the first element of the reversed container. //! @brief Returns const reverse iterator to the first element of the reversed container.
//! //!
@@ -836,7 +845,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_reverse_iterator crbegin() const; const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns reverse iterator to the one after the last element of the reversed container. //! @brief Returns reverse iterator to the one after the last element of the reversed container.
//! //!
@@ -848,7 +857,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
reverse_iterator rend(); reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const reverse iterator to the one after the last element of the reversed container. //! @brief Returns const reverse iterator to the one after the last element of the reversed container.
//! //!
@@ -860,7 +869,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_reverse_iterator rend() const; const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns const reverse iterator to the one after the last element of the reversed container. //! @brief Returns const reverse iterator to the one after the last element of the reversed container.
//! //!
@@ -872,7 +881,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
const_reverse_iterator crend() const; const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns container's capacity. //! @brief Returns container's capacity.
//! //!
@@ -883,7 +892,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
static size_type capacity(); static size_type capacity() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns container's capacity. //! @brief Returns container's capacity.
//! //!
@@ -894,7 +903,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
static size_type max_size(); static size_type max_size() BOOST_CONTAINER_NOEXCEPT;
//! @brief Returns the number of stored elements. //! @brief Returns the number of stored elements.
//! //!
@@ -905,7 +914,7 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
size_type size() const; size_type size() const BOOST_CONTAINER_NOEXCEPT;
//! @brief Queries if the container contains elements. //! @brief Queries if the container contains elements.
//! //!
@@ -917,7 +926,13 @@ public:
//! //!
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
bool empty() const; bool empty() const BOOST_CONTAINER_NOEXCEPT;
#else
friend void swap(static_vector &x, static_vector &y)
{
x.swap(y);
}
#endif // BOOST_CONTAINER_DOXYGEN_INVOKED #endif // BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1026,7 +1041,8 @@ inline void swap(static_vector<V, C1> & x, static_vector<V, C2> & y);
#else #else
template<typename V, std::size_t C1, std::size_t C2> template<typename V, std::size_t C1, std::size_t C2>
inline void swap(static_vector<V, C1> & x, static_vector<V, C2> & y) inline void swap(static_vector<V, C1> & x, static_vector<V, C2> & y
, typename container_detail::enable_if_c< C1 != C2>::type * = 0)
{ {
x.swap(y); x.swap(y);
} }

View File

@@ -89,7 +89,11 @@ class vector_const_iterator
//Constructors //Constructors
vector_const_iterator() BOOST_CONTAINER_NOEXCEPT vector_const_iterator() BOOST_CONTAINER_NOEXCEPT
#ifndef NDEBUG
: m_ptr() : m_ptr()
#else
// No value initialization of m_ptr() to speed up things a bit:
#endif
{} {}
//Pointer like operators //Pointer like operators
@@ -107,13 +111,13 @@ class vector_const_iterator
{ ++m_ptr; return *this; } { ++m_ptr; return *this; }
vector_const_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT vector_const_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT
{ Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } { return vector_const_iterator(m_ptr++); }
vector_const_iterator& operator--() BOOST_CONTAINER_NOEXCEPT vector_const_iterator& operator--() BOOST_CONTAINER_NOEXCEPT
{ --m_ptr; return *this; } { --m_ptr; return *this; }
vector_const_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT vector_const_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT
{ Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } { return vector_const_iterator(m_ptr--); }
//Arithmetic //Arithmetic
vector_const_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT vector_const_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT
@@ -125,11 +129,11 @@ class vector_const_iterator
friend vector_const_iterator operator+(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT friend vector_const_iterator operator+(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT
{ return vector_const_iterator(x.m_ptr+off); } { return vector_const_iterator(x.m_ptr+off); }
friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT friend vector_const_iterator operator+(difference_type off, vector_const_iterator right) BOOST_CONTAINER_NOEXCEPT
{ return vector_const_iterator(off + right.m_ptr); } { right.m_ptr += off; return right; }
friend vector_const_iterator operator-(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT friend vector_const_iterator operator-(vector_const_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT
{ return vector_const_iterator(x.m_ptr-off); } { left.m_ptr += off; return left; }
friend difference_type operator-(const vector_const_iterator &left, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT friend difference_type operator-(const vector_const_iterator &left, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT
{ return left.m_ptr - right.m_ptr; } { return left.m_ptr - right.m_ptr; }
@@ -159,9 +163,10 @@ template <class Pointer>
class vector_iterator class vector_iterator
: public vector_const_iterator<Pointer> : public vector_const_iterator<Pointer>
{ {
typedef vector_const_iterator<Pointer> base_t;
public: public:
explicit vector_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT explicit vector_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT
: vector_const_iterator<Pointer>(ptr) : base_t(ptr)
{} {}
public: public:
@@ -173,6 +178,7 @@ class vector_iterator
//Constructors //Constructors
vector_iterator() BOOST_CONTAINER_NOEXCEPT vector_iterator() BOOST_CONTAINER_NOEXCEPT
: base_t()
{} {}
//Pointer like operators //Pointer like operators
@@ -180,7 +186,7 @@ class vector_iterator
{ return *this->m_ptr; } { return *this->m_ptr; }
value_type* operator->() const BOOST_CONTAINER_NOEXCEPT value_type* operator->() const BOOST_CONTAINER_NOEXCEPT
{ return container_detail::to_raw_pointer(this->m_ptr); } { return container_detail::to_raw_pointer(this->m_ptr); }
reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT
{ return this->m_ptr[off]; } { return this->m_ptr[off]; }
@@ -190,13 +196,13 @@ class vector_iterator
{ ++this->m_ptr; return *this; } { ++this->m_ptr; return *this; }
vector_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT vector_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT
{ pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } { return vector_iterator(this->m_ptr++); }
vector_iterator& operator--() BOOST_CONTAINER_NOEXCEPT vector_iterator& operator--() BOOST_CONTAINER_NOEXCEPT
{ --this->m_ptr; return *this; } { --this->m_ptr; return *this; }
vector_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT vector_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT
{ vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } { return vector_iterator(this->m_ptr--); }
// Arithmetic // Arithmetic
vector_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT vector_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT
@@ -205,14 +211,14 @@ class vector_iterator
vector_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT vector_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT
{ this->m_ptr -= off; return *this; } { this->m_ptr -= off; return *this; }
friend vector_iterator operator+(const vector_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT friend vector_iterator operator+(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT
{ return vector_iterator(x.m_ptr+off); } { left.m_ptr += off; return left; }
friend vector_iterator operator+(difference_type off, const vector_iterator& right) BOOST_CONTAINER_NOEXCEPT friend vector_iterator operator+(difference_type off, vector_iterator right) BOOST_CONTAINER_NOEXCEPT
{ return vector_iterator(off + right.m_ptr); } { right.m_ptr += off; return right; }
friend vector_iterator operator-(const vector_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT friend vector_iterator operator-(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT
{ return vector_iterator(x.m_ptr-off); } { left.m_ptr -= off; return left; }
}; };
template <class T, class Allocator> template <class T, class Allocator>
@@ -271,35 +277,38 @@ struct vector_alloc_holder
//Constructor, does not throw //Constructor, does not throw
vector_alloc_holder() vector_alloc_holder()
BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value) BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value)
: Allocator(), m_start(), m_size(0), m_capacity(0) : Allocator(), m_start(), m_size(), m_capacity()
{} {}
//Constructor, does not throw //Constructor, does not throw
template<class AllocConvertible> template<class AllocConvertible>
explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT
: Allocator(boost::forward<AllocConvertible>(a)), m_start(), m_size(0), m_capacity(0) : Allocator(boost::forward<AllocConvertible>(a)), m_start(), m_size(), m_capacity()
{} {}
//Constructor, does not throw //Constructor, does not throw
template<class AllocConvertible> template<class AllocConvertible>
explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
: Allocator(boost::forward<AllocConvertible>(a)), m_start(), m_size(), m_capacity() : Allocator(boost::forward<AllocConvertible>(a))
, m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this
{ {
m_start = this->allocation_command m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first;
(allocate_new, cap, cap, m_capacity, m_start).first;
} }
//Constructor, does not throw //Constructor, does not throw
explicit vector_alloc_holder(size_type cap) explicit vector_alloc_holder(size_type initial_size)
: Allocator(), m_start(), m_size(), m_capacity() : Allocator()
, m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this
{ {
m_start = this->allocation_command m_start = this->allocation_command
(allocate_new, cap, cap, m_capacity, m_start).first; (allocate_new, initial_size, initial_size, m_capacity, m_start).first;
} }
vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT
: Allocator(boost::move(static_cast<Allocator&>(holder))) : Allocator(boost::move(static_cast<Allocator&>(holder)))
, m_start(holder.m_start), m_size(holder.m_size), m_capacity(holder.m_capacity) , m_start(holder.m_start)
, m_size(holder.m_size)
, m_capacity(holder.m_capacity)
{ {
holder.m_start = pointer(); holder.m_start = pointer();
holder.m_size = holder.m_capacity = 0; holder.m_size = holder.m_capacity = 0;
@@ -311,6 +320,9 @@ struct vector_alloc_holder
(allocate_new, cap, cap, m_capacity, m_start).first; (allocate_new, cap, cap, m_capacity, m_start).first;
} }
void first_allocation_same_allocator_type(size_type cap)
{ this->first_allocation(cap); }
//Destructor //Destructor
~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT
{ {
@@ -347,6 +359,9 @@ struct vector_alloc_holder
container_detail::do_swap(this->m_start, x.m_start); container_detail::do_swap(this->m_start, x.m_start);
container_detail::do_swap(this->m_size, x.m_size); container_detail::do_swap(this->m_size, x.m_size);
container_detail::do_swap(this->m_capacity, x.m_capacity); container_detail::do_swap(this->m_capacity, x.m_capacity);
//And now the allocator
container_detail::bool_<allocator_traits_type::propagate_on_container_swap::value> flag;
container_detail::swap_alloc(this->alloc(), x.alloc(), flag);
} }
void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT
@@ -400,43 +415,50 @@ struct vector_alloc_holder<Allocator, container_detail::integral_constant<unsign
//Constructor, does not throw //Constructor, does not throw
vector_alloc_holder() vector_alloc_holder()
BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value) BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value)
: Allocator(), m_size(0) : Allocator(), m_size()
{} {}
//Constructor, does not throw //Constructor, does not throw
template<class AllocConvertible> template<class AllocConvertible>
explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT
: Allocator(boost::forward<AllocConvertible>(a)), m_size(0) : Allocator(boost::forward<AllocConvertible>(a)), m_size()
{} {}
//Constructor, does not throw //Constructor, does not throw
template<class AllocConvertible> template<class AllocConvertible>
explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type cap) explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
: Allocator(boost::forward<AllocConvertible>(a)), m_size() : Allocator(boost::forward<AllocConvertible>(a))
, m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this
{ {
this->first_allocation(cap); this->first_allocation(initial_size);
} }
//Constructor, does not throw //Constructor, does not throw
explicit vector_alloc_holder(size_type cap) explicit vector_alloc_holder(size_type initial_size)
: Allocator(), m_size() : Allocator()
, m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this
{ {
this->first_allocation(cap); this->first_allocation(initial_size);
} }
vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder)
: Allocator(boost::move(static_cast<Allocator&>(holder))) : Allocator(boost::move(static_cast<Allocator&>(holder)))
, m_size() , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this
{ {
this->priv_move_construct_impl(holder); ::boost::container::uninitialized_move_alloc_n
(this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, this->start());
} }
template<class OtherAllocator, class OtherAllocatorVersion> template<class OtherAllocator, class OtherAllocatorVersion>
vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END holder) vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END holder)
: Allocator() : Allocator()
, m_size() , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort
{ {
this->priv_move_construct_impl(holder); //Different allocator type so we must check we have enough storage
const size_type n = holder.m_size;
this->first_allocation(n);
::boost::container::uninitialized_move_alloc_n
(this->alloc(), container_detail::to_raw_pointer(holder.start()), n, this->start());
} }
void first_allocation(size_type cap) void first_allocation(size_type cap)
@@ -446,6 +468,9 @@ struct vector_alloc_holder<Allocator, container_detail::integral_constant<unsign
} }
} }
void first_allocation_same_allocator_type(size_type)
{}
//Destructor //Destructor
~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT
{} {}
@@ -458,7 +483,7 @@ struct vector_alloc_holder<Allocator, container_detail::integral_constant<unsign
template<class OtherAllocator, class OtherAllocatorVersion> template<class OtherAllocator, class OtherAllocatorVersion>
void swap(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x) void swap(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x)
{ {
if(this->m_size > x.capacity() || x.m_size > this->capacity()){ if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){
throw_bad_alloc(); throw_bad_alloc();
} }
this->priv_swap_members_impl(x); this->priv_swap_members_impl(x);
@@ -484,19 +509,6 @@ struct vector_alloc_holder<Allocator, container_detail::integral_constant<unsign
private: private:
template<class OtherAllocator, class OtherAllocatorVersion>
void priv_move_construct_impl(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &holder)
{ //Containers with version 0 allocators can't be moved
const size_type n = holder.m_size;
this->first_allocation(n);
//Copy first new elements in pos
container_detail::move_insert_range_proxy<Allocator, const value_type*, value_type*> proxy
(this->alloc(), container_detail::to_raw_pointer(holder.start()));
proxy.uninitialized_copy_n_and_update
(container_detail::to_raw_pointer(this->start()), n);
this->m_size = n;
}
template<class OtherAllocator, class OtherAllocatorVersion> template<class OtherAllocator, class OtherAllocatorVersion>
void priv_swap_members_impl(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x) void priv_swap_members_impl(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x)
{ {
@@ -530,7 +542,10 @@ template <class T, class Allocator>
#endif #endif
class vector class vector
{ {
container_detail::vector_alloc_holder<Allocator> m_holder; typedef container_detail::integral_constant
<unsigned, boost::container::container_detail::version
<Allocator>::value > alloc_version;
boost::container::container_detail::vector_alloc_holder<Allocator, alloc_version> m_holder;
/// @cond /// @cond
typedef container_detail::vector_alloc_holder<Allocator> base_t; typedef container_detail::vector_alloc_holder<Allocator> base_t;
typedef allocator_traits<Allocator> allocator_traits_type; typedef allocator_traits<Allocator> allocator_traits_type;
@@ -566,9 +581,6 @@ class vector
typedef container_detail::integral_constant<unsigned, 0> allocator_v0; typedef container_detail::integral_constant<unsigned, 0> allocator_v0;
typedef container_detail::integral_constant<unsigned, 1> allocator_v1; typedef container_detail::integral_constant<unsigned, 1> allocator_v1;
typedef container_detail::integral_constant<unsigned, 2> allocator_v2; typedef container_detail::integral_constant<unsigned, 2> allocator_v2;
typedef container_detail::integral_constant
<unsigned, boost::container::container_detail::version
<Allocator>::value > alloc_version;
typedef constant_iterator<T, difference_type> cvalue_iterator; typedef constant_iterator<T, difference_type> cvalue_iterator;
/// @endcond /// @endcond
@@ -609,8 +621,7 @@ class vector
explicit vector(size_type n) explicit vector(size_type n)
: m_holder(n) : m_holder(n)
{ {
this->priv_first_allocation_fill boost::container::uninitialized_default_alloc_n(this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start()));
(container_detail::insert_default_constructed_n_proxy<Allocator, T*> (this->m_holder.alloc()), n);
} }
//! <b>Effects</b>: Constructs a vector //! <b>Effects</b>: Constructs a vector
@@ -623,8 +634,8 @@ class vector
vector(size_type n, const T& value) vector(size_type n, const T& value)
: m_holder(n) : m_holder(n)
{ {
this->priv_first_allocation_fill boost::container::uninitialized_fill_alloc_n
(container_detail::insert_n_copies_proxy<Allocator, T*> (this->m_holder.alloc(), value), n); (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start()));
} }
//! <b>Effects</b>: Constructs a vector that will use a copy of allocator a //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
@@ -637,8 +648,8 @@ class vector
vector(size_type n, const T& value, const allocator_type& a) vector(size_type n, const T& value, const allocator_type& a)
: m_holder(a, n) : m_holder(a, n)
{ {
this->priv_first_allocation_fill boost::container::uninitialized_fill_alloc_n
(container_detail::insert_n_copies_proxy<Allocator, T*> (this->m_holder.alloc(), value), n); (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start()));
} }
//! <b>Effects</b>: Constructs a vector //! <b>Effects</b>: Constructs a vector
@@ -676,9 +687,9 @@ class vector
vector(const vector &x) vector(const vector &x)
: m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size())
{ {
this->priv_first_allocation_fill ::boost::container::uninitialized_copy_or_move_alloc_n_source
(container_detail::insert_range_proxy<Allocator, const T*, T*> ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())
(this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); , x.size(), container_detail::to_raw_pointer(this->m_holder.start()));
} }
//! <b>Effects</b>: Move constructor. Moves mx's resources to *this. //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
@@ -717,9 +728,9 @@ class vector
vector(const vector &x, const allocator_type &a) vector(const vector &x, const allocator_type &a)
: m_holder(a, x.size()) : m_holder(a, x.size())
{ {
this->priv_first_allocation_fill ::boost::container::uninitialized_copy_or_move_alloc_n_source
(container_detail::insert_range_proxy<Allocator, const T*, T*> ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())
(this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())), x.size()); , x.size(), container_detail::to_raw_pointer(this->m_holder.start()));
} }
//! <b>Effects</b>: Move constructor using the specified allocator. //! <b>Effects</b>: Move constructor using the specified allocator.
@@ -737,10 +748,11 @@ class vector
} }
else{ else{
const size_type n = mx.size(); const size_type n = mx.size();
this->m_holder.first_allocation(n); this->m_holder.first_allocation_same_allocator_type(n);
this->priv_first_allocation_fill ::boost::container::uninitialized_move_alloc_n_source
(container_detail::move_insert_range_proxy<Allocator, const T*, T*> ( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start())
(this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start())), n); , n, container_detail::to_raw_pointer(this->m_holder.start()));
this->m_holder.m_size = n;
} }
} }
@@ -767,17 +779,7 @@ class vector
vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x)
{ {
if (&x != this){ if (&x != this){
allocator_type &this_alloc = this->m_holder.alloc(); this->priv_copy_assign(boost::move(x), alloc_version());
const allocator_type &x_alloc = x.m_holder.alloc();
container_detail::bool_<allocator_traits_type::
propagate_on_container_copy_assignment::value> flag;
if(flag && this_alloc != x_alloc){
this->clear();
this->shrink_to_fit();
}
container_detail::assign_alloc(this_alloc, x_alloc, flag);
this->assign( container_detail::to_raw_pointer(x.m_holder.start())
, container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size));
} }
return *this; return *this;
} }
@@ -794,25 +796,7 @@ class vector
//iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable<allocator_type>::value);) //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable<allocator_type>::value);)
BOOST_CONTAINER_NOEXCEPT BOOST_CONTAINER_NOEXCEPT
{ {
if (&x != this){ this->priv_move_assign(boost::move(x), alloc_version());
allocator_type &this_alloc = this->m_holder.alloc();
allocator_type &x_alloc = x.m_holder.alloc();
//If allocators are equal we can just swap pointers
if(this_alloc == x_alloc){
//Destroy objects but retain memory in case x reuses it in the future
this->clear();
this->m_holder.swap(x.m_holder);
//Move allocator if needed
container_detail::bool_<allocator_traits_type::
propagate_on_container_move_assignment::value> flag;
container_detail::move_alloc(this_alloc, x_alloc, flag);
}
//If unequal allocators, then do a one by one move
else{
this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start()))
, boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)));
}
}
return *this; return *this;
} }
@@ -829,8 +813,7 @@ class vector
template<class OtherAllocator, class OtherAllocatorVersion> template<class OtherAllocator, class OtherAllocatorVersion>
vector& operator=(BOOST_RV_REF_BEG vector<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END x) vector& operator=(BOOST_RV_REF_BEG vector<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END x)
{ {
this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) this->priv_move_assign(boost::move(x), alloc_version());
, boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)));
return *this; return *this;
} }
@@ -1259,8 +1242,8 @@ class vector
} }
else{ else{
typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type; typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type;
this->priv_forward_range_insert_at_end this->priv_forward_range_insert_no_capacity
(1, type(this->m_holder.alloc(), ::boost::forward<Args>(args)...), alloc_version()); (this->cend().get_ptr(), 1, type(this->m_holder.alloc(), ::boost::forward<Args>(args)...), alloc_version());
} }
} }
@@ -1300,7 +1283,8 @@ class vector
container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \
<Allocator, T* BOOST_PP_ENUM_TRAILING_PARAMS(n, P)> proxy \ <Allocator, T* BOOST_PP_ENUM_TRAILING_PARAMS(n, P)> proxy \
(this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \
this->priv_forward_range_insert_at_end(1, proxy, alloc_version()); \ this->priv_forward_range_insert_no_capacity \
(this->cend().get_ptr(), 1, proxy, alloc_version()); \
} \ } \
} \ } \
\ \
@@ -1482,9 +1466,6 @@ class vector
{ {
//Just swap internals in case of !allocator_v0. Otherwise, deep swap //Just swap internals in case of !allocator_v0. Otherwise, deep swap
this->m_holder.swap(x.m_holder); this->m_holder.swap(x.m_holder);
//And now the allocator
container_detail::bool_<allocator_traits_type::propagate_on_container_swap::value> flag;
container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), flag);
} }
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1531,6 +1512,125 @@ class vector
private: private:
template<class OtherAllocator, class AllocVersion>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value &&
!container_detail::is_same<OtherAllocator, allocator_type>::value
>::type * = 0)
{
if(this->capacity() < x.size()){
throw_bad_alloc();
}
this->priv_move_assign_impl(boost::move(x), AllocVersion());
}
template<class OtherAllocator, class AllocVersion>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value ||
container_detail::is_same<OtherAllocator, allocator_type>::value
>::type * = 0)
{
this->priv_move_assign_impl(boost::move(x), AllocVersion());
}
template<class OtherAllocator, class AllocVersion>
void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value
>::type * = 0)
{
T* const this_start = container_detail::to_raw_pointer(m_holder.start());
T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
const size_type this_sz = m_holder.m_size;
const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
if (this_sz < other_sz){
move_n(other_start, this_sz, this_start); // may throw
uninitialized_move_alloc_n( this->m_holder.alloc(), other_start + this_sz
, other_sz - this_sz, this_start + this_sz); // may throw
}
else
{
move_n(other_start, other_sz, this_start);
destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz);
}
this->m_holder.m_size = other_sz;
}
template<class OtherAllocator, class AllocVersion>
void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
, AllocVersion
, typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value
>::type * = 0)
{
//for move constructor, no aliasing (&x != this) is assummed.
allocator_type &this_alloc = this->m_holder.alloc();
allocator_type &x_alloc = x.m_holder.alloc();
//If allocators are equal we can just swap pointers
if(this_alloc == x_alloc){
//Destroy objects but retain memory in case x reuses it in the future
this->clear();
this->m_holder.swap(x.m_holder);
//Move allocator if needed
container_detail::bool_<allocator_traits_type::
propagate_on_container_move_assignment::value> flag;
container_detail::move_alloc(this_alloc, x_alloc, flag);
}
//If unequal allocators, then do a one by one move
else{
//TO-DO: optimize this
this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start()))
, boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)));
}
}
template<class AllocVersion>
void priv_copy_assign(const vector &x, AllocVersion
, typename container_detail::enable_if_c
< container_detail::is_same<AllocVersion, allocator_v0>::value
>::type * = 0)
{
T* const this_start = container_detail::to_raw_pointer(m_holder.start());
T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
const size_type this_sz = m_holder.m_size;
const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
if (this_sz < other_sz){
copy_or_move_n(other_start, this_sz, this_start); // may throw
uninitialized_copy_or_move_alloc_n( this->m_holder.alloc(), other_start + this_sz
, other_sz - this_sz, this_start + this_sz); // may throw
}
else
{
copy_or_move_n(other_start, other_sz, this_start);
destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz);
}
this->m_holder.m_size = other_sz;
}
template<class AllocVersion>
void priv_copy_assign(const vector &x, AllocVersion
, typename container_detail::enable_if_c
< !container_detail::is_same<AllocVersion, allocator_v0>::value
>::type * = 0)
{
allocator_type &this_alloc = this->m_holder.alloc();
const allocator_type &x_alloc = x.m_holder.alloc();
container_detail::bool_<allocator_traits_type::
propagate_on_container_copy_assignment::value> flag;
if(flag && this_alloc != x_alloc){
this->clear();
this->shrink_to_fit();
}
container_detail::assign_alloc(this_alloc, x_alloc, flag);
this->assign( container_detail::to_raw_pointer(x.m_holder.start())
, container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size));
}
void priv_reserve(size_type, allocator_v0) void priv_reserve(size_type, allocator_v0)
{ {
throw_bad_alloc(); throw_bad_alloc();
@@ -1540,20 +1640,17 @@ class vector
{ {
//There is not enough memory, allocate a new buffer //There is not enough memory, allocate a new buffer
pointer p = this->m_holder.allocate(new_cap); pointer p = this->m_holder.allocate(new_cap);
//We will reuse insert code, so create a dummy input iterator
container_detail::insert_range_proxy<Allocator, boost::move_iterator<T*>, T*>
proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0));
//Backwards (and possibly forward) expansion //Backwards (and possibly forward) expansion
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc; ++this->num_alloc;
#endif #endif
this->priv_range_insert_new_allocation T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start());
( container_detail::to_raw_pointer(p) const size_type sz = m_holder.m_size;
, new_cap ::boost::container::uninitialized_move_alloc_n_source
, container_detail::to_raw_pointer(this->m_holder.start()) ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) );
, 0 destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz);
, proxy); this->m_holder.start(p);
this->m_holder.capacity(new_cap);
} }
void priv_reserve(size_type new_cap, allocator_v2) void priv_reserve(size_type new_cap, allocator_v2)
@@ -1575,14 +1672,13 @@ class vector
#endif #endif
this->m_holder.capacity(real_cap); this->m_holder.capacity(real_cap);
} }
//If there is no forward expansion, move objects //If there is no forward expansion, move objects
else{ else{
//We will reuse insert code, so create a dummy input iterator
container_detail::insert_range_proxy<Allocator, boost::move_iterator<T*>, T*>
proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0));
//Backwards (and possibly forward) expansion //Backwards (and possibly forward) expansion
if(ret.second){ if(ret.second){
//We will reuse insert code, so create a dummy input iterator
container_detail::insert_range_proxy<Allocator, boost::move_iterator<T*>, T*>
proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0));
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_bwd; ++this->num_expand_bwd;
#endif #endif
@@ -1595,26 +1691,28 @@ class vector
} }
//New buffer //New buffer
else{ else{
//Backwards (and possibly forward) expansion
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc; ++this->num_alloc;
#endif #endif
this->priv_range_insert_new_allocation T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start());
( container_detail::to_raw_pointer(ret.first) const size_type sz = m_holder.m_size;
, real_cap ::boost::container::uninitialized_move_alloc_n_source
, container_detail::to_raw_pointer(this->m_holder.start()) ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) );
, 0 destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz);
, proxy); this->m_holder.start(ret.first);
this->m_holder.capacity(real_cap);
} }
} }
} }
template<class Proxy> template<class Proxy>
void priv_first_allocation_fill(Proxy proxy, size_type n) void priv_uninitialized_fill(Proxy proxy, size_type n) const
{ {
//Copy first new elements in pos //Copy first new elements in pos
proxy.uninitialized_copy_n_and_update proxy.uninitialized_copy_n_and_update
(container_detail::to_raw_pointer(this->m_holder.start()), n); (container_detail::to_raw_pointer(this->m_holder.start()), n);
this->m_holder.m_size = n; //m_holder.size was already initialized to n in vector_alloc_holder's constructor
} }
void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT
@@ -1644,19 +1742,35 @@ class vector
, ::boost::forward<U>(x)), alloc_version()); , ::boost::forward<U>(x)), alloc_version());
} }
template <class U> void priv_push_back(const T &x)
void priv_push_back(BOOST_FWD_REF(U) x)
{ {
if (this->m_holder.m_size < this->m_holder.capacity()){ if (this->m_holder.m_size < this->m_holder.capacity()){
//There is more memory, just construct a new object at the end //There is more memory, just construct a new object at the end
allocator_traits_type::construct allocator_traits_type::construct
( this->m_holder.alloc() ( this->m_holder.alloc()
, container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size)
, ::boost::forward<U>(x) ); , x );
++this->m_holder.m_size; ++this->m_holder.m_size;
} }
else{ else{
this->priv_insert(this->cend(), ::boost::forward<U>(x)); container_detail::insert_copy_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
this->priv_forward_range_insert_no_capacity(this->cend().get_ptr(), 1, proxy, alloc_version());
}
}
void priv_push_back(BOOST_RV_REF(T) x)
{
if (this->m_holder.m_size < this->m_holder.capacity()){
//There is more memory, just construct a new object at the end
allocator_traits_type::construct
( this->m_holder.alloc()
, container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size)
, ::boost::move(x) );
++this->m_holder.m_size;
}
else{
container_detail::insert_move_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
this->priv_forward_range_insert_no_capacity(this->cend().get_ptr(), 1, proxy, alloc_version());
} }
} }
@@ -1712,23 +1826,28 @@ class vector
} }
} }
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
(const pointer &pos, const size_type, const InsertionProxy , allocator_v0)
{
throw_bad_alloc();
return iterator(pos);
}
template <class InsertionProxy> template <class InsertionProxy>
iterator priv_forward_range_insert iterator priv_forward_range_insert
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0)
{ {
//Check if we have enough memory or try to expand current memory //Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
if (n <= remaining){ if (n > remaining){
this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
}
else{
//This will trigger an error //This will trigger an error
throw_bad_alloc(); throw_bad_alloc();
} }
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos); return iterator(this->m_holder.start() + n_pos);
} }
@@ -1739,40 +1858,49 @@ class vector
//Check if we have enough memory or try to expand current memory //Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
if (n <= remaining){ if (n > remaining){
this->priv_range_insert_at_end_expand_forward(n, insert_range_proxy);
}
else{
//This will trigger an error //This will trigger an error
throw_bad_alloc(); throw_bad_alloc();
} }
this->priv_range_insert_at_end_expand_forward(n, insert_range_proxy);
return this->end(); return this->end();
} }
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1)
{
//Check if we have enough memory or try to expand current memory
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
const size_type new_cap = this->m_holder.next_capacity(n);
T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap));
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_range_insert_new_allocation
( new_buf, new_cap, raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos);
}
template <class InsertionProxy> template <class InsertionProxy>
iterator priv_forward_range_insert iterator priv_forward_range_insert
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1)
{ {
//Check if we have enough memory or try to expand current memory //Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos); T *const raw_pos = container_detail::to_raw_pointer(pos);
if (n <= remaining){ if (n <= remaining){
const size_type n_pos = pos - this->m_holder.start();
this->priv_range_insert_expand_forward this->priv_range_insert_expand_forward
(raw_pos, n, insert_range_proxy); (raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos);
} }
else{ else{
const size_type new_cap = this->m_holder.next_capacity(n); return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version());
T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap));
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_range_insert_new_allocation
( new_buf, new_cap, raw_pos, n, insert_range_proxy);
} }
return iterator(this->m_holder.start() + n_pos);
} }
template <class InsertionProxy> template <class InsertionProxy>
@@ -1782,61 +1910,73 @@ class vector
return this->priv_forward_range_insert(this->cend().get_ptr(), n, insert_range_proxy, allocator_v1()); return this->priv_forward_range_insert(this->cend().get_ptr(), n, insert_range_proxy, allocator_v1());
} }
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2)
{
//Check if we have enough memory or try to expand current memory
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
size_type real_cap = 0;
//There is not enough memory, allocate a new
//buffer or expand the old one.
std::pair<pointer, bool> ret = (this->m_holder.allocation_command
(allocate_new | expand_fwd | expand_bwd,
this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start()));
//Buffer reallocated
if(ret.second){
//Forward expansion, delay insertion
if(this->m_holder.start() == ret.first){
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_fwd;
#endif
this->m_holder.capacity(real_cap);
//Expand forward
this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
}
//Backwards (and possibly forward) expansion
else{
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_bwd;
#endif
this->priv_range_insert_expand_backwards
( container_detail::to_raw_pointer(ret.first)
, real_cap, raw_pos, n, insert_range_proxy);
}
}
//New buffer
else{
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_range_insert_new_allocation
( container_detail::to_raw_pointer(ret.first)
, real_cap, raw_pos, n, insert_range_proxy);
}
return iterator(this->m_holder.start() + n_pos);
}
template <class InsertionProxy> template <class InsertionProxy>
iterator priv_forward_range_insert iterator priv_forward_range_insert
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2)
{ {
//Check if we have enough memory or try to expand current memory //Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
bool same_buffer_start = n <= remaining; bool same_buffer_start = n <= remaining;
if (!same_buffer_start){ if (!same_buffer_start){
size_type real_cap = 0; return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version());
//There is not enough memory, allocate a new
//buffer or expand the old one.
std::pair<pointer, bool> ret = (this->m_holder.allocation_command
(allocate_new | expand_fwd | expand_bwd,
this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start()));
//Buffer reallocated
if(ret.second){
//Forward expansion, delay insertion
if(this->m_holder.start() == ret.first){
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_fwd;
#endif
this->m_holder.capacity(real_cap);
//Expand forward
this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
}
//Backwards (and possibly forward) expansion
else{
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_bwd;
#endif
this->priv_range_insert_expand_backwards
( container_detail::to_raw_pointer(ret.first)
, real_cap, raw_pos, n, insert_range_proxy);
}
}
//New buffer
else{
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_range_insert_new_allocation
( container_detail::to_raw_pointer(ret.first)
, real_cap, raw_pos, n, insert_range_proxy);
}
} }
else{ else{
//Expand forward //Expand forward
const size_type n_pos = pos - this->m_holder.start();
T *const raw_pos = container_detail::to_raw_pointer(pos);
this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos);
} }
return iterator(this->m_holder.start() + n_pos);
} }
template <class InsertionProxy> template <class InsertionProxy>
@@ -1979,7 +2119,8 @@ class vector
//Case B: //Case B:
else if((first_pos + shift_count) >= limit_pos){ else if((first_pos + shift_count) >= limit_pos){
//All uninitialized_moved //All uninitialized_moved
::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); ::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count);
hole_size = last_pos + shift_count - limit_pos; hole_size = last_pos + shift_count - limit_pos;
} }
//Case C: //Case C:

View File

@@ -59,6 +59,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "throw_exception_test", "thr
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfiguration) = preSolution GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug Debug = Debug
@@ -127,6 +135,14 @@ Global
{5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Debug.Build.0 = 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.ActiveCfg = Release|Win32
{5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Release.Build.0 = 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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection EndGlobalSection

View File

@@ -172,6 +172,9 @@
<File <File
RelativePath="..\..\test\set_test.hpp"> RelativePath="..\..\test\set_test.hpp">
</File> </File>
<File
RelativePath="..\..\test\static_vector_test.hpp">
</File>
<File <File
RelativePath="..\..\test\util.hpp"> RelativePath="..\..\test\util.hpp">
</File> </File>
@@ -221,6 +224,9 @@
<File <File
RelativePath="..\..\..\..\boost\container\stable_vector.hpp"> RelativePath="..\..\..\..\boost\container\stable_vector.hpp">
</File> </File>
<File
RelativePath="..\..\..\..\boost\container\static_vector.hpp">
</File>
<File <File
RelativePath="..\..\..\..\boost\container\string.hpp"> RelativePath="..\..\..\..\boost\container\string.hpp">
</File> </File>
@@ -325,6 +331,26 @@
</File> </File>
</Filter> </Filter>
</Filter> </Filter>
<Filter
Name="bench"
Filter="">
<File
RelativePath="..\..\bench\varray.hpp">
</File>
<Filter
Name="detail"
Filter="">
<File
RelativePath="..\..\bench\detail\varray.hpp">
</File>
<File
RelativePath="..\..\bench\detail\varray_concept.hpp">
</File>
<File
RelativePath="..\..\bench\detail\varray_util.hpp">
</File>
</Filter>
</Filter>
</Files> </Files>
<Globals> <Globals>
</Globals> </Globals>

View File

@@ -21,7 +21,7 @@ rule test_all
for local fileb in [ glob *.cpp ] for local fileb in [ glob *.cpp ]
{ {
all_rules += [ run $(fileb) all_rules += [ run $(fileb) /boost/timer//boost_timer /boost/system//boost_system /boost/thread//boost_thread
: # additional args : # additional args
: # test-files : # test-files
: # requirements : # requirements

View File

@@ -1,92 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_MOVE_TEST_MOVABLE_HPP
#define BOOST_MOVE_TEST_MOVABLE_HPP
//[movable_definition
//header file "movable.hpp"
#include <boost/move/move.hpp>
//A movable class
class movable
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable)
int value_;
public:
movable() : value_(1){}
//Move constructor and assignment
movable(BOOST_RV_REF(movable) m)
{ value_ = m.value_; m.value_ = 0; }
movable & operator=(BOOST_RV_REF(movable) m)
{ value_ = m.value_; m.value_ = 0; return *this; }
bool moved() const //Observer
{ return value_ == 0; }
};
class copy_movable
{
BOOST_COPYABLE_AND_MOVABLE(copy_movable)
int value_;
public:
copy_movable(int value = 1) : value_(value){}
//Move constructor and assignment
copy_movable(BOOST_RV_REF(copy_movable) m)
{ value_ = m.value_; m.value_ = 0; }
copy_movable(const copy_movable &m)
{ value_ = m.value_; }
copy_movable & operator=(BOOST_RV_REF(copy_movable) m)
{ value_ = m.value_; m.value_ = 0; return *this; }
copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m)
{ value_ = m.value_; return *this; }
bool moved() const //Observer
{ return value_ == 0; }
bool operator==(const copy_movable& m) const
{ return value_ == m.value_; }
};
struct copy_movable_wrapper
{
copy_movable cm;
};
copy_movable produce()
{ return copy_movable(); }
namespace boost{
template<>
struct has_nothrow_move<movable>
{
static const bool value = true;
};
template<>
struct has_nothrow_move<copy_movable>
{
static const bool value = true;
};
} //namespace boost{
//]
#endif //BOOST_MOVE_TEST_MOVABLE_HPP

View File

@@ -53,23 +53,26 @@ class movable_int
movable_int & operator= (int i) movable_int & operator= (int i)
{ this->m_int = i; return *this; } { this->m_int = i; return *this; }
bool operator ==(const movable_int &mi) const ~movable_int()
{ return this->m_int == mi.m_int; } { this->m_int = 0; }
bool operator !=(const movable_int &mi) const friend bool operator ==(const movable_int &l, const movable_int &r)
{ return this->m_int != mi.m_int; } { return l.m_int == r.m_int; }
bool operator <(const movable_int &mi) const friend bool operator !=(const movable_int &l, const movable_int &r)
{ return this->m_int < mi.m_int; } { return l.m_int != r.m_int; }
bool operator <=(const movable_int &mi) const friend bool operator <(const movable_int &l, const movable_int &r)
{ return this->m_int <= mi.m_int; } { return l.m_int < r.m_int; }
bool operator >=(const movable_int &mi) const friend bool operator <=(const movable_int &l, const movable_int &r)
{ return this->m_int >= mi.m_int; } { return l.m_int <= r.m_int; }
bool operator >(const movable_int &mi) const friend bool operator >=(const movable_int &l, const movable_int &r)
{ return this->m_int > mi.m_int; } { 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 int get_int() const
{ return m_int; } { return m_int; }
@@ -84,6 +87,9 @@ class movable_int
int m_int; int m_int;
}; };
inline movable_int produce_movable_int()
{ return movable_int(); }
template<class E, class T> template<class E, class T>
std::basic_ostream<E, T> & operator<< std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, movable_int const & p) (std::basic_ostream<E, T> & os, movable_int const & p)
@@ -93,7 +99,6 @@ std::basic_ostream<E, T> & operator<<
return os; return os;
} }
template<> template<>
struct is_copyable<movable_int> struct is_copyable<movable_int>
{ {
@@ -121,6 +126,9 @@ class movable_and_copyable_int
: m_int(mmi.m_int) : m_int(mmi.m_int)
{ mmi.m_int = 0; } { 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) movable_and_copyable_int &operator= (BOOST_COPY_ASSIGN_REF(movable_and_copyable_int) mi)
{ this->m_int = mi.m_int; return *this; } { this->m_int = mi.m_int; return *this; }
@@ -130,23 +138,23 @@ class movable_and_copyable_int
movable_and_copyable_int & operator= (int i) movable_and_copyable_int & operator= (int i)
{ this->m_int = i; return *this; } { this->m_int = i; return *this; }
bool operator ==(const movable_and_copyable_int &mi) const friend bool operator ==(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int == mi.m_int; } { return l.m_int == r.m_int; }
bool operator !=(const movable_and_copyable_int &mi) const friend bool operator !=(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int != mi.m_int; } { return l.m_int != r.m_int; }
bool operator <(const movable_and_copyable_int &mi) const friend bool operator <(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int < mi.m_int; } { return l.m_int < r.m_int; }
bool operator <=(const movable_and_copyable_int &mi) const friend bool operator <=(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int <= mi.m_int; } { return l.m_int <= r.m_int; }
bool operator >=(const movable_and_copyable_int &mi) const friend bool operator >=(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int >= mi.m_int; } { return l.m_int >= r.m_int; }
bool operator >(const movable_and_copyable_int &mi) const friend bool operator >(const movable_and_copyable_int &l, const movable_and_copyable_int &r)
{ return this->m_int > mi.m_int; } { return l.m_int > r.m_int; }
int get_int() const int get_int() const
{ return m_int; } { return m_int; }
@@ -161,6 +169,9 @@ class movable_and_copyable_int
int m_int; int m_int;
}; };
inline movable_and_copyable_int produce_movable_and_copyable_int()
{ return movable_and_copyable_int(); }
template<class E, class T> template<class E, class T>
std::basic_ostream<E, T> & operator<< std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, movable_and_copyable_int const & p) (std::basic_ostream<E, T> & os, movable_and_copyable_int const & p)
@@ -194,23 +205,29 @@ class copyable_int
copyable_int & operator= (int i) copyable_int & operator= (int i)
{ this->m_int = i; return *this; } { this->m_int = i; return *this; }
bool operator ==(const copyable_int &mi) const copyable_int & operator= (const copyable_int &ci)
{ return this->m_int == mi.m_int; } { this->m_int = ci.m_int; return *this; }
bool operator !=(const copyable_int &mi) const ~copyable_int()
{ return this->m_int != mi.m_int; } { this->m_int = 0; }
bool operator <(const copyable_int &mi) const friend bool operator ==(const copyable_int &l, const copyable_int &r)
{ return this->m_int < mi.m_int; } { return l.m_int == r.m_int; }
bool operator <=(const copyable_int &mi) const friend bool operator !=(const copyable_int &l, const copyable_int &r)
{ return this->m_int <= mi.m_int; } { return l.m_int != r.m_int; }
bool operator >=(const copyable_int &mi) const friend bool operator <(const copyable_int &l, const copyable_int &r)
{ return this->m_int >= mi.m_int; } { return l.m_int < r.m_int; }
bool operator >(const copyable_int &mi) const friend bool operator <=(const copyable_int &l, const copyable_int &r)
{ return this->m_int > mi.m_int; } { 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 int get_int() const
{ return m_int; } { return m_int; }
@@ -225,6 +242,9 @@ class copyable_int
int m_int; int m_int;
}; };
inline copyable_int produce_copyable_int()
{ return copyable_int(); }
template<class E, class T> template<class E, class T>
std::basic_ostream<E, T> & operator<< std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, copyable_int const & p) (std::basic_ostream<E, T> & os, copyable_int const & p)
@@ -254,6 +274,9 @@ class non_copymovable_int
: m_int(a) : m_int(a)
{} {}
~non_copymovable_int()
{ m_int = 0; }
bool operator ==(const non_copymovable_int &mi) const bool operator ==(const non_copymovable_int &mi) const
{ return this->m_int == mi.m_int; } { return this->m_int == mi.m_int; }

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "movable.hpp" #include "movable_int.hpp"
using namespace boost::container; using namespace boost::container;

View File

@@ -216,7 +216,12 @@ int vector_test()
stdvector->push_back(int(1)); stdvector->push_back(int(1));
if(!test::CheckEqualContainers(boostvector, stdvector)) return 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();
boostvector->pop_back(); boostvector->pop_back();
stdvector->pop_back(); stdvector->pop_back();