Default initialization for vector-like containers

Complexity guarantees for associative container constructors and ordered input ranges
Fix for #9166
Added benchmark for associative containers
Removed check for old MSVC compilers and #pragma once.

[SVN r85970]
This commit is contained in:
Ion Gaztañaga
2013-09-26 21:35:57 +00:00
parent 11ba31a353
commit 254095432e
57 changed files with 1489 additions and 281 deletions
+48 -3
View File
@@ -25,6 +25,12 @@ class SimpleAllocator
public:
typedef T value_type;
template <class U>
SimpleAllocator(SimpleAllocator<U>)
: allocate_called_(false)
, deallocate_called_(false)
{}
SimpleAllocator()
: allocate_called_(false)
, deallocate_called_(false)
@@ -132,6 +138,13 @@ class ComplexAllocator
#define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
template<class U>
void construct(U *p, boost::container::default_init_t)
{
construct_called_ = true;
::new (p) U;
}
//getters
bool allocate_called() const
{ return allocate_called_; }
@@ -157,13 +170,13 @@ class ComplexAllocator
class copymovable
{
bool copymoveconstructed_;
bool moved_;
BOOST_COPYABLE_AND_MOVABLE(copymovable)
public:
bool copymoveconstructed_;
bool moved_;
copymovable(int, int, int)
: copymoveconstructed_(false), moved_(false)
{}
@@ -314,6 +327,22 @@ int main()
SAllocTraits::select_on_container_copy_construction(s_alloc);
//construct
{
copymovable c;
c.copymoveconstructed_ = true;
c.copymoveconstructed_ = true;
CAllocTraits::construct(c_alloc, &c);
if(!c_alloc.construct_called() || c.copymoveconstructed() || c.moved()){
return 1;
}
}
{
int i = 5;
CAllocTraits::construct(c_alloc, &i, boost::container::default_init);
if(!c_alloc.construct_called() || i != 5){
return 1;
}
}
{
copymovable c;
copymovable c2;
@@ -330,6 +359,22 @@ int main()
return 1;
}
}
{
copymovable c;
c.copymoveconstructed_ = true;
c.copymoveconstructed_ = true;
SAllocTraits::construct(s_alloc, &c);
if(c.copymoveconstructed() || c.moved()){
return 1;
}
}
{
int i = 4;
SAllocTraits::construct(s_alloc, &i, boost::container::default_init);
if(i != 4){
return 1;
}
}
{
copymovable c;
copymovable c2;
+4
View File
@@ -332,6 +332,10 @@ int main ()
return 1;
if(test::vector_test<MyCopyDeque>())
return 1;
if(!test::default_init_test< deque<int, test::default_init_allocator<int> > >()){
std::cerr << "Default init test failed" << std::endl;
return 1;
}
}
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE);
+1 -1
View File
@@ -11,7 +11,7 @@
#ifndef BOOST_CONTAINER_DUMMY_TEST_ALLOCATOR_HPP
#define BOOST_CONTAINER_DUMMY_TEST_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
#if (defined _MSC_VER)
# pragma once
#endif
+1 -1
View File
@@ -11,7 +11,7 @@
#ifndef BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP
#define BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
#if (defined _MSC_VER)
# pragma once
#endif
+1 -1
View File
@@ -11,7 +11,7 @@
#ifndef BOOST_CONTAINER_HEAP_ALLOCATOR_V1_HPP
#define BOOST_CONTAINER_HEAP_ALLOCATOR_V1_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
#if (defined _MSC_VER)
# pragma once
#endif
+35
View File
@@ -66,6 +66,36 @@ void recursive_vector_test()//Test for recursive types
}
}
bool default_init_test()//Test for default initialization
{
typedef stable_vector<int, test::default_init_allocator<int> > svector_t;
const std::size_t Capacity = 100;
{
test::default_init_allocator<int>::reset_pattern(0);
svector_t v(Capacity, default_init);
svector_t::iterator it = v.begin();
//Compare with the pattern
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(*it != static_cast<int>(i))
return false;
}
}
{
test::default_init_allocator<int>::reset_pattern(100);
svector_t v;
v.resize(Capacity, default_init);
svector_t::iterator it = v.begin();
//Compare with the pattern
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(*it != static_cast<int>(i+100))
return false;
}
}
return true;
}
int main()
{
recursive_vector_test();
@@ -102,6 +132,11 @@ int main()
if(test::vector_test<MyCopyVector>())
return 1;
if(!test::default_init_test< stable_vector<int, test::default_init_allocator<int> > >()){
std::cerr << "Default init test failed" << std::endl;
return 1;
}
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE);
if(!boost::container::test::test_emplace
< stable_vector<test::EmplaceInt>, Options>())
+50
View File
@@ -611,6 +611,53 @@ void test_sv_elem(T const& t)
v.emplace_back(N/2, t);
}
bool default_init_test()//Test for default initialization
{
typedef static_vector<int, 100> di_vector_t;
const std::size_t Capacity = 100;
{
di_vector_t v;
int *p = v.data();
for(std::size_t i = 0; i != Capacity; ++i, ++p){
*p = static_cast<int>(i);
}
//Destroy the vector, p stilll pointing to the storage
v.~di_vector_t();
di_vector_t &rv = *::new(&v)di_vector_t(Capacity, default_init);
di_vector_t::iterator it = rv.begin();
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(*it != static_cast<int>(i))
return false;
}
v.~di_vector_t();
}
{
di_vector_t v;
int *p = v.data();
for(std::size_t i = 0; i != Capacity; ++i, ++p){
*p = static_cast<int>(i+100);
}
v.resize(Capacity, default_init);
di_vector_t::iterator it = v.begin();
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(*it != static_cast<int>(i+100))
return false;
}
}
return true;
}
int main(int, char* [])
{
using boost::container::test::movable_and_copyable_int;
@@ -727,6 +774,9 @@ int main(int, char* [])
BOOST_TEST(counting_value::count() == 0);
test_sv_elem<shptr_value, 10>(shptr_value(50));
test_sv_elem<movable_and_copyable_int, 10>(movable_and_copyable_int(50));
BOOST_TEST(default_init_test() == true);
return boost::report_errors();
}
+4
View File
@@ -151,6 +151,10 @@ int main()
return 1;
if(test_expand_bwd())
return 1;
if(!test::default_init_test< vector<int, test::default_init_allocator<int> > >()){
std::cerr << "Default init test failed" << std::endl;
return 1;
}
MyEnumVector v;
Test t;
+119 -1
View File
@@ -31,12 +31,130 @@
#include <boost/move/utility.hpp>
#include <boost/move/iterator.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/static_assert.hpp>
#include "insert_test.hpp"
namespace boost{
namespace container {
namespace test{
//
template<int Dummy = 0>
class default_init_allocator_base
{
protected:
static unsigned char s_pattern;
static bool s_ascending;
public:
static void reset_pattern(unsigned char value)
{ s_pattern = value; }
static void set_ascending(bool enable)
{ s_ascending = enable; }
};
template<int Dummy>
unsigned char default_init_allocator_base<Dummy>::s_pattern = 0u;
template<int Dummy>
bool default_init_allocator_base<Dummy>::s_ascending = true;
template<class T>
class default_init_allocator
: public default_init_allocator_base<0>
{
typedef default_init_allocator_base<0> base_t;
public:
typedef T value_type;
default_init_allocator()
{}
template <class U>
default_init_allocator(default_init_allocator<U>)
{}
T* allocate(std::size_t n)
{
//Initialize memory to a pattern
T *const p = ::new T[n];
unsigned char *puc_raw = reinterpret_cast<unsigned char*>(p);
std::size_t max = sizeof(T)*n;
if(base_t::s_ascending){
for(std::size_t i = 0; i != max; ++i){
puc_raw[i] = static_cast<unsigned char>(s_pattern++);
}
}
else{
for(std::size_t i = 0; i != max; ++i){
puc_raw[i] = static_cast<unsigned char>(s_pattern--);
}
}
return p;
}
void deallocate(T *p, std::size_t)
{ delete[] p; }
};
template<class T>
inline bool check_ascending_byte_pattern(const T&t)
{
const unsigned char *pch = &reinterpret_cast<const unsigned char &>(t);
const std::size_t max = sizeof(T);
for(std::size_t i = 1; i != max; ++i){
if( (pch[i-1] != ((unsigned char)(pch[i]-1u))) ){
return false;
}
}
return true;
}
template<class T>
inline bool check_descending_byte_pattern(const T&t)
{
const unsigned char *pch = &reinterpret_cast<const unsigned char &>(t);
const std::size_t max = sizeof(T);
for(std::size_t i = 1; i != max; ++i){
if( (pch[i-1] != ((unsigned char)(pch[i]+1u))) ){
return false;
}
}
return true;
}
template<class IntDefaultInitAllocVector>
bool default_init_test()//Test for default initialization
{
const std::size_t Capacity = 100;
{
test::default_init_allocator<int>::reset_pattern(0);
test::default_init_allocator<int>::set_ascending(true);
IntDefaultInitAllocVector v(Capacity, default_init);
typename IntDefaultInitAllocVector::iterator it = v.begin();
//Compare with the pattern
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(!test::check_ascending_byte_pattern(*it))
return false;
}
}
{
test::default_init_allocator<int>::reset_pattern(100);
test::default_init_allocator<int>::set_ascending(false);
IntDefaultInitAllocVector v;
v.resize(Capacity, default_init);
typename IntDefaultInitAllocVector::iterator it = v.begin();
//Compare with the pattern
for(std::size_t i = 0; i != Capacity; ++i, ++it){
if(!test::check_descending_byte_pattern(*it))
return false;
}
}
return true;
}
template<class V1, class V2>
bool vector_copyable_only(V1 *, V2 *, boost::container::container_detail::false_type)
{
@@ -100,7 +218,7 @@ template<class MyBoostVector>
int vector_test()
{
typedef std::vector<int> MyStdVector;
typedef typename MyBoostVector::value_type IntType;
typedef typename MyBoostVector::value_type IntType;
const int max = 100;
if(!test_range_insertion<MyBoostVector>()){