diff --git a/bench/Jamfile.v2 b/bench/Jamfile.v2 index 25add18..cc1e715 100644 --- a/bench/Jamfile.v2 +++ b/bench/Jamfile.v2 @@ -21,7 +21,7 @@ rule test_all for local fileb in [ glob *.cpp ] { - all_rules += [ run $(fileb) /boost/timer//boost_timer /boost/system//boost_system /boost/thread//boost_thread + all_rules += [ run $(fileb) /boost/timer//boost_timer : # additional args : # test-files : # requirements diff --git a/bench/bench_set.cpp b/bench/bench_set.cpp new file mode 100644 index 0000000..662d11b --- /dev/null +++ b/bench/bench_set.cpp @@ -0,0 +1,348 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include "boost/container/flat_set.hpp" +#include +#include +#include +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +#ifdef NDEBUG +static const std::size_t N = 5000; +#else +static const std::size_t N = 500; +#endif + +void compare_times(cpu_times time_numerator, cpu_times time_denominator){ + std::cout << "----------------------------------------------" << '\n'; + std::cout << " wall = " << ((double)time_numerator.wall/(double)time_denominator.wall) << std::endl; + std::cout << "----------------------------------------------" << '\n' << std::endl; +} + +std::vector sorted_unique_range; +std::vector sorted_range; +std::vector random_unique_range; +std::vector random_range; + +void fill_ranges() +{ + sorted_unique_range.resize(N); + sorted_range.resize(N); + random_unique_range.resize(N); + random_range.resize(N); + std::srand (0); + //random_range + std::generate(random_unique_range.begin(), random_unique_range.end(), std::rand); + random_unique_range.erase(std::unique(random_unique_range.begin(), random_unique_range.end()), random_unique_range.end()); + //random_range + random_range = random_unique_range; + random_range.insert(random_range.end(), random_unique_range.begin(), random_unique_range.end()); + //sorted_unique_range + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + sorted_unique_range[i] = static_cast(i); + } + //sorted_range + sorted_range = sorted_unique_range; + sorted_range.insert(sorted_range.end(), sorted_unique_range.begin(), sorted_unique_range.end()); + std::sort(sorted_range.begin(), sorted_range.end()); +} + +template +cpu_times construct_time() +{ + cpu_timer sur_timer, sr_timer, rur_timer, rr_timer, copy_timer, assign_timer, destroy_timer; + //sur_timer.stop();sr_timer.stop();rur_timer.stop();rr_timer.stop();destroy_timer.stop(); + + cpu_timer total_time; + total_time.resume(); + + for(std::size_t i = 0; i != N; ++i){ + { + sur_timer.resume(); + T t(sorted_unique_range.begin(), sorted_unique_range.end()); + sur_timer.stop(); + } + { + sr_timer.resume(); + T t(sorted_range.begin(), sorted_range.end()); + sr_timer.stop(); + copy_timer.resume(); + T taux(t); + copy_timer.stop(); + assign_timer.resume(); + t = taux;; + assign_timer.stop(); + } + { + rur_timer.resume(); + T t(random_unique_range.begin(), random_unique_range.end()); + rur_timer.stop(); + } + { + rr_timer.resume(); + T t(random_range.begin(), random_range.end()); + rr_timer.stop(); + destroy_timer.resume(); + } + destroy_timer.stop(); + } + total_time.stop(); + + std::cout << " Construct sorted_unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Construct sorted_range " << boost::timer::format(sr_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Copy sorted range " << boost::timer::format(copy_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Assign sorted range " << boost::timer::format(assign_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Construct random_unique_range " << boost::timer::format(rur_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Construct random_range " << boost::timer::format(rr_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Destroy " << boost::timer::format(destroy_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws wall\n") << std::endl; + return total_time.elapsed(); +} + +template +cpu_times insert_time() +{ + cpu_timer sur_timer,sr_timer,rur_timer,rr_timer,destroy_timer; + sur_timer.stop();sr_timer.stop();rur_timer.stop();rr_timer.stop(); + + cpu_timer total_time; + total_time.resume(); + + for(std::size_t i = 0; i != N; ++i){ + { + sur_timer.resume(); + T t; + t.insert(sorted_unique_range.begin(), sorted_unique_range.end()); + sur_timer.stop(); + } + { + sr_timer.resume(); + T t; + t.insert(sorted_range.begin(), sorted_range.end()); + sr_timer.stop(); + } + { + rur_timer.resume(); + T t; + t.insert(random_unique_range.begin(), random_unique_range.end()); + rur_timer.stop(); + } + { + rr_timer.resume(); + T t; + t.insert(random_range.begin(), random_range.end()); + rr_timer.stop(); + } + } + total_time.stop(); + + std::cout << " Insert sorted_unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Insert sorted_range " << boost::timer::format(sr_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Insert random_unique_range " << boost::timer::format(rur_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Insert random_range " << boost::timer::format(rr_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws wall\n") << std::endl; + return total_time.elapsed(); +} + +template +cpu_times search_time() +{ + cpu_timer find_timer, lower_timer, upper_timer, equal_range_timer, count_timer; + + T t(sorted_unique_range.begin(), sorted_unique_range.end()); + + cpu_timer total_time; + total_time.resume(); + + for(std::size_t i = 0; i != N; ++i){ + //Find + { + std::size_t found = 0; + find_timer.resume(); + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.find(sorted_unique_range[i])); + } + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.find(sorted_unique_range[i])); + } + find_timer.stop(); + if(found/2 != t.size()){ + std::cout << "ERROR! all elements not found" << std::endl; + } + } + //Lower + { + std::size_t found = 0; + lower_timer.resume(); + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.lower_bound(sorted_unique_range[i])); + } + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.lower_bound(sorted_unique_range[i])); + } + lower_timer.stop(); + if(found/2 != t.size()){ + std::cout << "ERROR! all elements not found" << std::endl; + } + } + //Upper + { + std::size_t found = 0; + upper_timer.resume(); + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.upper_bound(sorted_unique_range[i])); + } + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.end() != t.upper_bound(sorted_unique_range[i])); + } + upper_timer.stop(); + if(found/2 != (t.size()-1)){ + std::cout << "ERROR! all elements not found" << std::endl; + } + } + //Equal + { + std::size_t found = 0; + std::pair ret; + equal_range_timer.resume(); + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + ret = t.equal_range(sorted_unique_range[i]); + found += static_cast(ret.first != ret.second); + } + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + ret = t.equal_range(sorted_unique_range[i]); + found += static_cast(ret.first != ret.second); + } + equal_range_timer.stop(); + if(found/2 != t.size()){ + std::cout << "ERROR! all elements not found" << std::endl; + } + } + //Count + { + std::size_t found = 0; + std::pair ret; + count_timer.resume(); + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.count(sorted_unique_range[i])); + } + for(std::size_t i = 0, max = sorted_unique_range.size(); i != max; ++i){ + found += static_cast(t.count(sorted_unique_range[i])); + } + count_timer.stop(); + if(found/2 != t.size()){ + std::cout << "ERROR! all elements not found" << std::endl; + } + } + } + total_time.stop(); + + std::cout << " Find " << boost::timer::format(find_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Lower Bound " << boost::timer::format(lower_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Upper Bound " << boost::timer::format(upper_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Equal Range " << boost::timer::format(equal_range_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Count " << boost::timer::format(count_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws wall\n") << std::endl; + return total_time.elapsed(); +} + +template +void extensions_time() +{ + cpu_timer sur_timer,sur_opt_timer; + sur_timer.stop();sur_opt_timer.stop(); + + for(std::size_t i = 0; i != N; ++i){ + { + sur_timer.resume(); + T t(sorted_unique_range.begin(), sorted_unique_range.end()); + sur_timer.stop(); + } + { + sur_opt_timer.resume(); + T t(boost::container::ordered_unique_range, sorted_unique_range.begin(), sorted_unique_range.end()); + sur_opt_timer.stop(); + } + + } + std::cout << " Construct sorted_unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << " Construct sorted_unique_range (extension) " << boost::timer::format(sur_opt_timer.elapsed(), boost::timer::default_places, "%ws wall\n"); + std::cout << "Total time (Extension/Standard):\n"; + compare_times(sur_opt_timer.elapsed(), sur_timer.elapsed()); +} + +template +void launch_tests(const char *BoostContName, const char *StdContName) +{ + try { + fill_ranges(); + { + std::cout << "Construct benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = construct_time< BoostClass >(); + + std::cout << "Construct benchmark:" << StdContName << std::endl; + cpu_times std_set_time = construct_time< StdClass >(); + + std::cout << "Total time (" << BoostContName << "/" << StdContName << "):\n"; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Insert benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = insert_time< BoostClass >(); + + std::cout << "Insert benchmark:" << StdContName << std::endl; + cpu_times std_set_time = insert_time< StdClass >(); + + std::cout << "Total time (" << BoostContName << "/" << StdContName << "):\n"; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Search benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = search_time< BoostClass >(); + + std::cout << "Search benchmark:" << StdContName << std::endl; + cpu_times std_set_time = search_time< StdClass >(); + + std::cout << "Total time (" << BoostContName << "/" << StdContName << "):\n"; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Extensions benchmark:" << BoostContName << std::endl; + extensions_time< BoostClass >(); + } + + }catch(std::exception e){ + std::cout << e.what(); + } +} + +int main() +{ + //set vs std::set + launch_tests< boost::container::set , std::set > + ("boost::container::set", "std::set");/* + //multiset vs std::set + launch_tests< boost::container::multiset , std::multiset > + ("boost::container::multiset", "std::multiset");*/ + //flat_set vs set + //launch_tests< boost::container::flat_set , boost::container::set > + //("boost::container::flat_set", "boost::container::set"); + //flat_multiset vs multiset + //launch_tests< boost::container::flat_multiset , boost::container::multiset > + //("boost::container::flat_multiset", "boost::container::multiset"); + return 1; +} diff --git a/bench/bench_static_vector.cpp b/bench/bench_static_vector.cpp index f36e145..71e48a9 100644 --- a/bench/bench_static_vector.cpp +++ b/bench/bench_static_vector.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/bench/detail/varray.hpp b/bench/detail/varray.hpp index e0729f0..874daae 100644 --- a/bench/detail/varray.hpp +++ b/bench/detail/varray.hpp @@ -293,7 +293,7 @@ public: //! @pre count <= capacity() //! - //! @brief Constructs a varray containing count default constructed Values. + //! @brief Constructs a varray containing count value initialized Values. //! //! @param count The number of values which will be contained in the container. //! @@ -616,7 +616,7 @@ public: //! @pre count <= capacity() //! //! @brief Inserts or erases elements at the end such that - //! the size becomes count. New elements are default constructed. + //! the size becomes count. New elements are value initialized. //! //! @param count The number of elements which will be stored in the container. //! diff --git a/bench/varray.hpp b/bench/varray.hpp index 1e15d82..8dcb5de 100644 --- a/bench/varray.hpp +++ b/bench/varray.hpp @@ -91,7 +91,7 @@ public: //! @pre count <= capacity() //! - //! @brief Constructs a varray containing count default constructed Values. + //! @brief Constructs a varray containing count value initialized Values. //! //! @param count The number of values which will be contained in the container. //! @@ -311,7 +311,7 @@ public: //! @pre count <= capacity() //! //! @brief Inserts or erases elements at the end such that - //! the size becomes count. New elements are default constructed. + //! the size becomes count. New elements are value initialized. //! //! @param count The number of elements which will be stored in the container. //! diff --git a/doc/container.qbk b/doc/container.qbk index 1238ce8..0c88b82 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -502,6 +502,52 @@ are a particular case where `static_vector` can be beneficial. [endsect] +[section:extended_functionality Extended functionality] + +[section:default_initialialization Default initialization for vector-like containers] + +STL and most other containers value initialize new elements in common operations like +`vector::resize(size_type n)` or `explicit vector::vector(size_type n)`. + +In some performance-sensitive environments, where vectors are used as a replacement for +variable-size buffers for file or network operations, +[@http://en.cppreference.com/w/cpp/language/value_initialization value initialization] +is a cost that is not negligible as elements are going to be overwritten by an external source +shortly after new elements are added to the container. + +[*Boost.Container] offers two new members for `vector`, `static_vector` and `stable_vector`: +`explicit container::container(size_type n, default_init_t)` and +`explicit container::resize(size_type n, default_init_t)`, where new elements are constructed +using [@http://en.cppreference.com/w/cpp/language/default_initialization default initialization]. + +[endsect] + +[/ +/a__section:get_stored_allocator Obtain stored allocator__a +/ +/STL containers offer a `get_allocator()` member to obtain a copy of the allocator that +/the container is using to allocate and construct elements. For performance reasons, some +/applications need o +/ +/http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html +/ +/a__endsect__a +/ +/a__section:ordered_range_insertion Ordered range insertion (a__'ordered_unique_range__a, a__'ordered_range__a) __a +/ +/a__endsect__a +/ +/a__section:constant_time_range_splice Constant-time range splice__a +/ +/a__endsect__a +/ +/a__section:previous_element_slist Slist previous element__a +/ +/a__endsect__a +/] + +[endsect] + [section:Cpp11_conformance C++11 Conformance] [*Boost.Container] aims for full C++11 conformance except reasoned deviations, diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 19c35a8..aa8194a 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -387,6 +388,10 @@ struct allocator_traits #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + static void priv_construct_dispatch2(boost::false_type, Alloc &, T *p, ::boost::container::default_init_t) + { ::new((void*)p) T; } #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) ///@endcond diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index 3b47b2f..271cc8b 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -135,20 +135,28 @@ class basic_string; struct ordered_range_t {}; +//! Value used to tag that the input range is +//! guaranteed to be ordered +static const ordered_range_t ordered_range = ordered_range_t(); + //! Type used to tag that the input range is //! guaranteed to be ordered and unique struct ordered_unique_range_t : public ordered_range_t {}; -//! Value used to tag that the input range is -//! guaranteed to be ordered -static const ordered_range_t ordered_range = ordered_range_t(); - //! Value used to tag that the input range is //! guaranteed to be ordered and unique static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t(); +//! Type used to tag that the input range is +//! guaranteed to be ordered and unique +struct default_init_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered and unique +static const default_init_t default_init = default_init_t(); /// @cond namespace detail_really_deep_namespace { @@ -161,6 +169,7 @@ struct dummy { (void)ordered_range; (void)ordered_unique_range; + (void)default_init; } }; diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 98b66ee..136b4f6 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -540,7 +540,7 @@ class deque : protected deque_base {} //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts n default contructed values. + //! and inserts n value initialized values. //! //! Throws: If allocator_type's default constructor or copy constructor //! throws or T's default or copy constructor throws. @@ -549,7 +549,24 @@ class deque : protected deque_base explicit deque(size_type n) : Base(n, allocator_type()) { - container_detail::insert_default_constructed_n_proxy proxy(this->alloc()); + container_detail::insert_value_initialized_n_proxy proxy(this->alloc()); + proxy.uninitialized_copy_n_and_update(this->begin(), n); + //deque_base will deallocate in case of exception... + } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + deque(size_type n, default_init_t) + : Base(n, allocator_type()) + { + container_detail::insert_default_initialized_n_proxy proxy(this->alloc()); proxy.uninitialized_copy_n_and_update(this->begin(), n); //deque_base will deallocate in case of exception... } @@ -949,9 +966,9 @@ class deque : protected deque_base { return allocator_traits_type::max_size(this->alloc()); } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: If memory allocation throws, or T's constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) @@ -961,7 +978,27 @@ class deque : protected deque_base this->priv_erase_last_n(len - new_size); else{ const size_type n = new_size - this->size(); - container_detail::insert_default_constructed_n_proxy proxy(this->alloc()); + container_detail::insert_value_initialized_n_proxy proxy(this->alloc()); + priv_insert_back_aux_impl(n, proxy); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + //! + //! Note: Non-standard extension + void resize(size_type new_size, default_init_t) + { + const size_type len = size(); + if (new_size < len) + this->priv_erase_last_n(len - new_size); + else{ + const size_type n = new_size - this->size(); + container_detail::insert_default_initialized_n_proxy proxy(this->alloc()); priv_insert_back_aux_impl(n, proxy); } } diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 47539b3..e42bcb3 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -99,19 +99,43 @@ struct insert_n_copies_proxy }; template -struct insert_default_constructed_n_proxy +struct insert_value_initialized_n_proxy { typedef ::boost::container::allocator_traits alloc_traits; typedef typename allocator_traits::size_type size_type; typedef typename allocator_traits::value_type value_type; - explicit insert_default_constructed_n_proxy(A &a) + explicit insert_value_initialized_n_proxy(A &a) : a_(a) {} 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_value_init_alloc_n(this->a_, n, p); } + + void copy_n_and_update(Iterator, size_type) const + { + BOOST_ASSERT(false); + } + + private: + A &a_; +}; + +template +struct insert_default_initialized_n_proxy +{ + typedef ::boost::container::allocator_traits alloc_traits; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + + explicit insert_default_initialized_n_proxy(A &a) + : a_(a) + {} + + void uninitialized_copy_n_and_update(Iterator p, size_type n) const + { boost::container::uninitialized_default_init_alloc_n(this->a_, n, p); } void copy_n_and_update(Iterator, size_type) const { diff --git a/include/boost/container/detail/algorithms.hpp b/include/boost/container/detail/algorithms.hpp index 072cf9c..7a4a868 100644 --- a/include/boost/container/detail/algorithms.hpp +++ b/include/boost/container/detail/algorithms.hpp @@ -35,13 +35,13 @@ namespace boost { namespace container { template -struct is_default_construct_iterator +struct is_value_init_construct_iterator { static const bool value = false; }; template -struct is_default_construct_iterator > +struct is_value_init_construct_iterator > { static const bool value = true; }; @@ -64,11 +64,17 @@ inline void construct_in_place(A &a, T* dest, InpIt source) //#endif template -inline void construct_in_place(A &a, T *dest, default_construct_iterator) +inline void construct_in_place(A &a, T *dest, value_init_construct_iterator) { boost::container::allocator_traits::construct(a, dest); } +template +inline void construct_in_place(A &a, T *dest, default_init_construct_iterator) +{ + boost::container::allocator_traits::construct(a, dest, default_init); +} + template inline void construct_in_place(A &a, T *dest, emplace_iterator ei) { diff --git a/include/boost/container/detail/allocator_version_traits.hpp b/include/boost/container/detail/allocator_version_traits.hpp index e051707..6df79da 100644 --- a/include/boost/container/detail/allocator_version_traits.hpp +++ b/include/boost/container/detail/allocator_version_traits.hpp @@ -92,8 +92,12 @@ struct allocator_version_traits static void deallocate_individual(Allocator &a, multiallocation_chain &holder) { - while(!holder.empty()){ - a.deallocate(holder.pop_front(), 1); + size_type n = holder.size(); + typename multiallocation_chain::iterator it = holder.begin(); + while(n--){ + pointer p = boost::intrusive::pointer_traits::pointer_to(*it); + ++it; + a.deallocate(p, 1); } } diff --git a/include/boost/container/detail/config_begin.hpp b/include/boost/container/detail/config_begin.hpp index 83c2cfe..664f092 100644 --- a/include/boost/container/detail/config_begin.hpp +++ b/include/boost/container/detail/config_begin.hpp @@ -46,4 +46,5 @@ #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site #pragma warning (disable : 4671) // the copy constructor is inaccessible #pragma warning (disable : 4584) // X is already a base-class of Y + #pragma warning (disable : 4510) // default constructor could not be generated #endif //BOOST_MSVC diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index 6865466..fef8aa0 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -68,6 +68,9 @@ struct scoped_deallocator pointer get() const { return m_ptr; } + void set(const pointer &p) + { m_ptr = p; } + void release() { m_ptr = 0; } }; @@ -87,6 +90,9 @@ struct null_scoped_deallocator pointer get() const { return pointer(); } + + void set(const pointer &) + {} }; //!A deleter for scoped_ptr that deallocates the memory @@ -249,6 +255,11 @@ class scoped_destructor void release() { pv_ = 0; } + + void set(value_type *ptr) { pv_ = ptr; } + + value_type *get() const { return pv_; } + private: value_type *pv_; A &a_; diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 0aad21f..f214d19 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -240,16 +240,24 @@ class flat_tree , const allocator_type& a = allocator_type()) : m_data(comp, a) { + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + //Call end() every iteration as reallocation might have invalidated iterators if(unique_insertion){ - this->insert_unique(first, last); + for ( ; first != last; ++first){ + this->insert_unique(this->cend(), *first); + } } else{ - this->insert_equal(first, last); + for ( ; first != last; ++first){ + this->insert_equal(this->cend(), *first); + } } } ~flat_tree() - { } + {} flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x) { m_data = x.m_data; return *this; } @@ -389,7 +397,11 @@ class flat_tree template void insert_unique(InIt first, InIt last) - { this->priv_insert_unique_loop(first, last); } + { + for ( ; first != last; ++first){ + this->insert_unique(*first); + } + } template void insert_equal(InIt first, InIt last @@ -487,7 +499,13 @@ class flat_tree >::type * = 0 #endif ) - { this->priv_insert_unique_loop_hint(first, last); } + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_unique(pos, *first); + ++pos; + } + } template void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last @@ -677,22 +695,21 @@ class flat_tree // set operations: iterator find(const key_type& k) { - const Compare &key_cmp = this->m_data.get_comp(); iterator i = this->lower_bound(k); - - if (i != this->end() && key_cmp(k, KeyOfValue()(*i))){ - i = this->end(); + iterator end_it = this->end(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; } return i; } const_iterator find(const key_type& k) const { - const Compare &key_cmp = this->m_data.get_comp(); const_iterator i = this->lower_bound(k); - if (i != this->end() && key_cmp(k, KeyOfValue()(*i))){ - i = this->end(); + const_iterator end_it = this->cend(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; } return i; } @@ -708,19 +725,19 @@ class flat_tree { return this->priv_lower_bound(this->begin(), this->end(), k); } const_iterator lower_bound(const key_type& k) const - { return this->priv_lower_bound(this->begin(), this->end(), k); } + { return this->priv_lower_bound(this->cbegin(), this->cend(), k); } iterator upper_bound(const key_type& k) { return this->priv_upper_bound(this->begin(), this->end(), k); } const_iterator upper_bound(const key_type& k) const - { return this->priv_upper_bound(this->begin(), this->end(), k); } + { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } std::pair equal_range(const key_type& k) { return this->priv_equal_range(this->begin(), this->end(), k); } std::pair equal_range(const key_type& k) const - { return this->priv_equal_range(this->begin(), this->end(), k); } + { return this->priv_equal_range(this->cbegin(), this->cend(), k); } size_type capacity() const { return this->m_data.m_vect.capacity(); } @@ -817,7 +834,6 @@ class flat_tree //in the remaining range [pos, end) return this->priv_insert_unique_prepare(pos, cend_it, val, commit_data); } - //return priv_insert_unique_prepare(val, commit_data); } template @@ -835,11 +851,11 @@ class flat_tree { const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; + size_type len = static_cast(last - first); RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type half = len >> 1; middle = first; middle += half; @@ -854,17 +870,18 @@ class flat_tree return first; } + template RanIt priv_upper_bound(RanIt first, RanIt last, const key_type & key) const { const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; + size_type len = static_cast(last - first); RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type half = len >> 1; middle = first; middle += half; @@ -885,11 +902,11 @@ class flat_tree { const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; - difference_type len = last - first, half; - RanIt middle, left, right; + size_type len = static_cast(last - first); + RanIt middle; - while (len > 0) { - half = len >> 1; + while (len) { + size_type half = len >> 1; middle = first; middle += half; @@ -902,10 +919,11 @@ class flat_tree len = half; } else { - left = this->priv_lower_bound(first, middle, key); - first += len; - right = this->priv_upper_bound(++middle, first, key); - return std::pair(left, right); + //Middle is equal to key + last = first; + last += len; + first = this->priv_lower_bound(first, middle, key); + return std::pair (first, this->priv_upper_bound(++middle, last, key)); } } return std::pair(first, first); @@ -924,24 +942,10 @@ class flat_tree { const_iterator pos(this->cend()); for ( ; first != last; ++first){ + //If ordered, then try hint version + //to achieve constant-time complexity per insertion pos = this->insert_equal(pos, *first); - } - } - - template - void priv_insert_unique_loop(InIt first, InIt last) - { - for ( ; first != last; ++first){ - this->insert_unique(*first); - } - } - - template - void priv_insert_unique_loop_ordered(InIt first, InIt last) - { - const_iterator pos(this->cend()); - for ( ; first != last; ++first){ - pos = this->insert_unique(pos, *first); + ++pos; } } }; diff --git a/include/boost/container/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index 500e6b9..5766a7c 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -148,79 +148,79 @@ class constant_iterator }; template -class default_construct_iterator +class value_init_construct_iterator : public std::iterator { - typedef default_construct_iterator this_type; + typedef value_init_construct_iterator this_type; public: - explicit default_construct_iterator(Difference range_size) + explicit value_init_construct_iterator(Difference range_size) : m_num(range_size){} //Constructors - default_construct_iterator() + value_init_construct_iterator() : m_num(0){} - default_construct_iterator& operator++() + value_init_construct_iterator& operator++() { increment(); return *this; } - default_construct_iterator operator++(int) + value_init_construct_iterator operator++(int) { - default_construct_iterator result (*this); + value_init_construct_iterator result (*this); increment(); return result; } - default_construct_iterator& operator--() + value_init_construct_iterator& operator--() { decrement(); return *this; } - default_construct_iterator operator--(int) + value_init_construct_iterator operator--(int) { - default_construct_iterator result (*this); + value_init_construct_iterator result (*this); decrement(); return result; } - friend bool operator== (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator== (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i.equal(i2); } - friend bool operator!= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator!= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i == i2); } - friend bool operator< (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator< (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i.less(i2); } - friend bool operator> (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator> (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i2 < i; } - friend bool operator<= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator<= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i > i2); } - friend bool operator>= (const default_construct_iterator& i, const default_construct_iterator& i2) + friend bool operator>= (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return !(i < i2); } - friend Difference operator- (const default_construct_iterator& i, const default_construct_iterator& i2) + friend Difference operator- (const value_init_construct_iterator& i, const value_init_construct_iterator& i2) { return i2.distance_to(i); } //Arithmetic - default_construct_iterator& operator+=(Difference off) + value_init_construct_iterator& operator+=(Difference off) { this->advance(off); return *this; } - default_construct_iterator operator+(Difference off) const + value_init_construct_iterator operator+(Difference off) const { - default_construct_iterator other(*this); + value_init_construct_iterator other(*this); other.advance(off); return other; } - friend default_construct_iterator operator+(Difference off, const default_construct_iterator& right) + friend value_init_construct_iterator operator+(Difference off, const value_init_construct_iterator& right) { return right + off; } - default_construct_iterator& operator-=(Difference off) + value_init_construct_iterator& operator-=(Difference off) { this->advance(-off); return *this; } - default_construct_iterator operator-(Difference off) const + value_init_construct_iterator operator-(Difference off) const { return *this + (-off); } //This pseudo-iterator's dereference operations have no sense since value is not @@ -258,6 +258,118 @@ class default_construct_iterator { return m_num - other.m_num; } }; +template +class default_init_construct_iterator + : public std::iterator + +{ + typedef default_init_construct_iterator this_type; + + public: + explicit default_init_construct_iterator(Difference range_size) + : m_num(range_size){} + + //Constructors + default_init_construct_iterator() + : m_num(0){} + + default_init_construct_iterator& operator++() + { increment(); return *this; } + + default_init_construct_iterator operator++(int) + { + default_init_construct_iterator result (*this); + increment(); + return result; + } + + default_init_construct_iterator& operator--() + { decrement(); return *this; } + + default_init_construct_iterator operator--(int) + { + default_init_construct_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const default_init_construct_iterator& i, const default_init_construct_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + default_init_construct_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + default_init_construct_iterator operator+(Difference off) const + { + default_init_construct_iterator other(*this); + other.advance(off); + return other; + } + + friend default_init_construct_iterator operator+(Difference off, const default_init_construct_iterator& right) + { return right + off; } + + default_init_construct_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + default_init_construct_iterator operator-(Difference off) const + { return *this + (-off); } + + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; + + private: + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { + static T dummy; + return dummy; + } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + + template class repeat_iterator : public std::iterator diff --git a/include/boost/container/detail/multiallocation_chain.hpp b/include/boost/container/detail/multiallocation_chain.hpp index 2e29f9c..bc9945a 100644 --- a/include/boost/container/detail/multiallocation_chain.hpp +++ b/include/boost/container/detail/multiallocation_chain.hpp @@ -243,10 +243,10 @@ class transform_multiallocation_chain iterator before_begin() { return iterator(holder_.before_begin()); } - +*/ iterator begin() - { return iterator(holder_.begin()); } - + { return iterator(this->MultiallocationChain::begin()); } +/* iterator end() { return iterator(holder_.end()); } diff --git a/include/boost/container/detail/node_alloc_holder.hpp b/include/boost/container/detail/node_alloc_holder.hpp index 4ab26c9..d94c2e9 100644 --- a/include/boost/container/detail/node_alloc_holder.hpp +++ b/include/boost/container/detail/node_alloc_holder.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ struct node_alloc_holder typedef typename allocator_traits_type::template portable_rebind_alloc::type NodeAlloc; typedef allocator_traits node_allocator_traits_type; + typedef container_detail::allocator_version_traits node_allocator_version_traits_type; typedef A ValAlloc; typedef typename node_allocator_traits_type::pointer NodePtr; typedef container_detail::scoped_deallocator Deallocator; @@ -233,45 +235,41 @@ struct node_alloc_holder (FwdIterator beg, difference_type n, Inserter inserter) { if(n){ - /* - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - ::boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), it); - node_deallocator.release(); - //This does not throw - typedef typename Node::hook_type hook_type; - ::new(static_cast(container_detail::to_raw_pointer(p))) hook_type; - return (p); - */ - typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; + typedef typename node_allocator_version_traits_type::multiallocation_chain multiallocation_chain; //Try to allocate memory in a single block typedef typename multiallocation_chain::iterator multialloc_iterator; multiallocation_chain mem; - this->node_alloc().allocate_individual(n, mem); + NodeAlloc &nalloc = this->node_alloc(); + node_allocator_version_traits_type::allocate_individual(nalloc, n, mem); multialloc_iterator itbeg(mem.begin()), itlast(mem.last()); mem.clear(); Node *p = 0; - NodeAlloc &nalloc = this->node_alloc(); BOOST_TRY{ + Deallocator node_deallocator(NodePtr(), nalloc); + container_detail::scoped_destructor sdestructor(nalloc, 0); while(n--){ p = container_detail::to_raw_pointer(&*itbeg); + node_deallocator.set(p); ++itbeg; //This can throw - Deallocator node_deallocator(p, nalloc); boost::container::construct_in_place(nalloc, container_detail::addressof(p->m_data), beg); + sdestructor.set(p); ++beg; - node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; ::new(static_cast(p)) hook_type; - //This can throw in some containers (predicate might throw) + //This can throw in some containers (predicate might throw). + //(sdestructor will destruct the node and node_deallocator will deallocate it in case of exception) inserter(*p); + sdestructor.set(0); } + sdestructor.release(); + node_deallocator.release(); } BOOST_CATCH(...){ mem.incorporate_after(mem.last(), &*itbeg, &*itlast, n); - this->node_alloc().deallocate_individual(mem); + node_allocator_version_traits_type::deallocate_individual(this->node_alloc(), mem); BOOST_RETHROW } BOOST_CATCH_END diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 6dcb1b7..2c3fdde 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -178,6 +178,34 @@ struct rbtree_node { m_data = ::boost::move(v); } }; +template +class insert_equal_end_hint_functor +{ + Icont &icont_; + + public: + insert_equal_end_hint_functor(Icont &icont) + : icont_(icont) + {} + + void operator()(Node &n) + { this->icont_.insert_equal(this->icont_.cend(), n); } +}; + +template +class push_back_functor +{ + Icont &icont_; + + public: + push_back_functor(Icont &icont) + : icont_(icont) + {} + + void operator()(Node &n) + { this->icont_.push_back(n); } +}; + }//namespace container_detail { namespace container_detail { @@ -405,11 +433,19 @@ class rbtree ) : AllocHolder(a, value_compare(comp)) { + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + const const_iterator end_it(this->cend()); if(unique_insertion){ - this->insert_unique(first, last); + for ( ; first != last; ++first){ + this->insert_unique(end_it, *first); + } } else{ - this->insert_equal(first, last); + for ( ; first != last; ++first){ + this->insert_equal(end_it, *first); + } } } @@ -426,12 +462,19 @@ class rbtree : AllocHolder(a, value_compare(comp)) { if(unique_insertion){ - this->insert_unique(first, last); + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + const const_iterator end_it(this->cend()); + for ( ; first != last; ++first){ + this->insert_unique(end_it, *first); + } } else{ //Optimized allocation and construction this->allocate_many_and_construct - (first, std::distance(first, last), insert_equal_end_hint_functor(this->icont())); + ( first, std::distance(first, last) + , insert_equal_end_hint_functor(this->icont())); } } @@ -447,7 +490,9 @@ class rbtree ) : AllocHolder(a, value_compare(comp)) { - this->insert_equal(first, last); + for ( ; first != last; ++first){ + this->push_back_impl(*first); + } } template @@ -464,7 +509,8 @@ class rbtree { //Optimized allocation and construction this->allocate_many_and_construct - (first, std::distance(first, last), push_back_functor(this->icont())); + ( first, std::distance(first, last) + , container_detail::push_back_functor(this->icont())); } rbtree(const rbtree& x) @@ -534,8 +580,8 @@ class rbtree rbtree& operator=(BOOST_RV_REF(rbtree) x) { if (&x != this){ - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); + NodeAlloc &this_alloc = this->get_stored_allocator(); + const NodeAlloc &x_alloc = x.get_stored_allocator(); //If allocators are equal we can just swap pointers if(this_alloc == x_alloc){ //Destroy and swap pointers @@ -678,8 +724,10 @@ class rbtree iterator insert_unique_commit(const value_type& v, insert_commit_data &data) { NodePtr tmp = AllocHolder::create_node(v); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; } template @@ -687,8 +735,10 @@ class rbtree (BOOST_FWD_REF(MovableConvertible) mv, insert_commit_data &data) { NodePtr tmp = AllocHolder::create_node(boost::forward(mv)); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; } std::pair insert_unique(const value_type& v) @@ -696,10 +746,10 @@ class rbtree insert_commit_data data; std::pair ret = this->insert_unique_check(KeyOfValue()(v), data); - if(!ret.second) - return ret; - return std::pair - (this->insert_unique_commit(v, data), true); + if(ret.second){ + ret.first = this->insert_unique_commit(v, data); + } + return ret; } template @@ -708,13 +758,22 @@ class rbtree insert_commit_data data; std::pair ret = this->insert_unique_check(KeyOfValue()(mv), data); - if(!ret.second) - return ret; - return std::pair - (this->insert_unique_commit(boost::forward(mv), data), true); + if(ret.second){ + ret.first = this->insert_unique_commit(boost::forward(mv), data); + } + return ret; } private: + + template + void push_back_impl(BOOST_FWD_REF(MovableConvertible) mv) + { + NodePtr tmp(AllocHolder::create_node(boost::forward(mv))); + //push_back has no-throw guarantee so avoid any deallocator/destroyer + this->icont().push_back(*tmp); + } + std::pair emplace_unique_impl(NodePtr p) { value_type &v = p->get_data(); @@ -760,15 +819,21 @@ class rbtree template iterator emplace_equal(Args&&... args) { - NodePtr p(AllocHolder::create_node(boost::forward(args)...)); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward(args)...)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { NodePtr p(AllocHolder::create_node(boost::forward(args)...)); - return iterator(this->icont().insert_equal(hint.get(), *p)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -792,16 +857,22 @@ class rbtree BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ + NodePtr tmp(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); \ + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); \ + destroy_deallocator.release(); \ + return ret; \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace_hint_equal(const_iterator hint \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert_equal(hint.get(), *p)); \ + NodePtr tmp(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); \ + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); \ + destroy_deallocator.release(); \ + return ret; \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) @@ -833,53 +904,53 @@ class rbtree template void insert_unique(InputIterator first, InputIterator last) { - if(this->empty()){ - //Insert with end hint, to achieve linear - //complexity if [first, last) is ordered - const_iterator hint(this->cend()); - for( ; first != last; ++first) - hint = this->insert_unique(hint, *first); - } - else{ - for( ; first != last; ++first) - this->insert_unique(*first); - } + for( ; first != last; ++first) + this->insert_unique(*first); } iterator insert_equal(const value_type& v) { - NodePtr p(AllocHolder::create_node(v)); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(v)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } template iterator insert_equal(BOOST_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(boost::forward(mv))); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward(mv))); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(this->icont().end(), *tmp)); + destroy_deallocator.release(); + return ret; } iterator insert_equal(const_iterator hint, const value_type& v) { - NodePtr p(AllocHolder::create_node(v)); - return iterator(this->icont().insert_equal(hint.get(), *p)); + NodePtr tmp(AllocHolder::create_node(v)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } template iterator insert_equal(const_iterator hint, BOOST_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(boost::forward(mv))); - return iterator(this->icont().insert_equal(hint.get(), *p)); + NodePtr tmp(AllocHolder::create_node(boost::forward(mv))); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_equal(hint.get(), *tmp)); + destroy_deallocator.release(); + return ret; } template void insert_equal(InputIterator first, InputIterator last) { - //Insert with end hint, to achieve linear - //complexity if [first, last) is ordered - const_iterator hint(this->cend()); for( ; first != last; ++first) - hint = this->insert_equal(hint, *first); + this->insert_equal(*first); } iterator erase(const_iterator position) @@ -930,41 +1001,6 @@ class rbtree return std::pair (const_iterator(ret.first), const_iterator(ret.second)); } - - private: - - class insert_equal_end_hint_functor; - friend class insert_equal_end_hint_functor; - - class insert_equal_end_hint_functor - { - Icont &icont_; - const iconst_iterator cend_; - - public: - insert_equal_end_hint_functor(Icont &icont) - : icont_(icont), cend_(this->icont_.cend()) - {} - - void operator()(Node &n) - { this->icont_.insert_equal(cend_, n); } - }; - - class push_back_functor; - friend class push_back_functor; - - class push_back_functor - { - Icont &icont_; - - public: - push_back_functor(Icont &icont) - : icont_(icont) - {} - - void operator()(Node &n) - { this->icont_.push_back(n); } - }; }; template :: ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_default_alloc_n +// uninitialized_value_init_alloc_n // ////////////////////////////////////////////////////////////////////////////// @@ -636,7 +636,7 @@ inline typename container_detail::enable_if_memcpy_copy_constructible:: template // F models ForwardIterator -inline F uninitialized_default_alloc_n(A &a, typename allocator_traits::difference_type n, F r) +inline F uninitialized_value_init_alloc_n(A &a, typename allocator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -655,6 +655,41 @@ inline F uninitialized_default_alloc_n(A &a, typename allocator_traits::diffe return r; } +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_default_init_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r); +//! \endcode +//! +//! Returns: r +template + // F models ForwardIterator +inline F uninitialized_default_init_alloc_n(A &a, typename allocator_traits::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits::construct(a, container_detail::to_raw_pointer(&*r), default_init); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits::destroy(a, container_detail::to_raw_pointer(&*back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_fill_alloc diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 9da14c9..8778de5 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -694,6 +694,8 @@ class flat_map //! search time plus N*size() insertion time. //! //! Note: If an element is inserted it might invalidate elements. + //! + //! Note: Non-standard extension. template void insert(ordered_unique_range_t, InputIterator first, InputIterator last) { m_flat_tree.insert_unique(ordered_unique_range, first, last); } @@ -798,7 +800,7 @@ class flat_map //! //! Complexity: log(size())+count(k) size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } //! Returns: An iterator pointing to the first element with key not less //! than k, or a.end() if such an element is not found. @@ -1487,6 +1489,8 @@ class flat_multimap //! search time plus N*size() insertion time. //! //! Note: If an element is inserted it might invalidate elements. + //! + //! Note: Non-standard extension. template void insert(ordered_range_t, InputIterator first, InputIterator last) { m_flat_tree.insert_equal(ordered_range, first, last); } diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 77711cc..eda8fbd 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -636,7 +636,7 @@ class flat_set //! //! Complexity: log(size())+count(k) size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } //! Returns: An iterator pointing to the first element with key not less //! than k, or a.end() if such an element is not found. diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 2eff808..8ebd5be 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -563,7 +563,7 @@ class list { return AllocHolder::max_size(); } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! //! Throws: If memory allocation throws, or T's copy constructor throws. //! @@ -571,8 +571,8 @@ class list void resize(size_type new_size) { if(!priv_try_shrink(new_size)){ - typedef default_construct_iterator default_iterator; - this->insert(this->cend(), default_iterator(new_size - this->size()), default_iterator()); + typedef value_init_construct_iterator value_init_iterator; + this->insert(this->cend(), value_init_iterator(new_size - this->size()), value_init_iterator()); } } diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index e0b5581..f4776e8 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -170,6 +170,8 @@ class map //! unique values. //! //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. template map( ordered_unique_range_t, InputIterator first, InputIterator last , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) @@ -711,7 +713,7 @@ class map //! //! Complexity: log(size())+count(k) size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + { return static_cast(m_tree.find(x) != m_tree.end()); } //! Returns: An iterator pointing to the first element with key not less //! than k, or a.end() if such an element is not found. @@ -971,6 +973,8 @@ class multimap //! Requires: [first ,last) must be ordered according to the predicate. //! //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. template multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index d215df4..96656f3 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -139,6 +139,8 @@ class set //! unique values. //! //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. template set( ordered_unique_range_t, InputIterator first, InputIterator last , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) @@ -556,7 +558,7 @@ class set //! //! Complexity: log(size())+count(k) size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + { return static_cast(m_tree.find(x) != m_tree.end()); } //! Returns: An iterator pointing to the first element with key not less //! than k, or a.end() if such an element is not found. @@ -770,6 +772,8 @@ class multiset //! Requires: [first ,last) must be ordered according to the predicate. //! //! Complexity: Linear in N. + //! + //! Note: Non-standard extension. template multiset( ordered_range_t, InputIterator first, InputIterator last , const Compare& comp = Compare() diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 37a3b52..9d2d761 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -588,7 +588,7 @@ class slist { return AllocHolder::max_size(); } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! //! Throws: If memory allocation throws, or T's copy constructor throws. //! @@ -597,8 +597,8 @@ class slist { const_iterator last_pos; if(!priv_try_shrink(new_size, last_pos)){ - typedef default_construct_iterator default_iterator; - this->insert_after(last_pos, default_iterator(new_size - this->size()), default_iterator()); + typedef value_init_construct_iterator value_init_iterator; + this->insert_after(last_pos, value_init_iterator(new_size - this->size()), value_init_iterator()); } } diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index c64a339..7b31cc4 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -123,8 +123,8 @@ struct node rebind_pointer::type > { - private: - node(); +// private: +// node(); public: typename ::boost::intrusive::pointer_traits::element_type value; @@ -568,7 +568,7 @@ class stable_vector } //! Effects: Constructs a stable_vector that will use a copy of allocator a - //! and inserts n default contructed values. + //! and inserts n value initialized values. //! //! Throws: If allocator_type's default constructor or copy constructor //! throws or T's default or copy constructor throws. @@ -583,6 +583,24 @@ class stable_vector cod.release(); } + //! Effects: Constructs a stable_vector that will use a copy of allocator a + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + stable_vector(size_type n, default_init_t) + : internal_data(), index() + { + stable_vector_detail::clear_on_destroy cod(*this); + this->resize(n, default_init); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + //! Effects: Constructs a stable_vector that will use a copy of allocator a //! and inserts n copies of value. //! @@ -960,17 +978,35 @@ class stable_vector { return this->index.max_size() - ExtraPointers; } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: If memory allocation throws, or T's default constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type n) { - typedef default_construct_iterator default_iterator; + typedef value_init_construct_iterator value_init_iterator; STABLE_VECTOR_CHECK_INVARIANT; if(n > this->size()) - this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); + this->insert(this->cend(), value_init_iterator(n - this->size()), value_init_iterator()); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default initialized. + //! + //! Throws: If memory allocation throws, or T's default constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + //! + //! Note: Non-standard extension + void resize(size_type n, default_init_t) + { + typedef default_init_construct_iterator default_init_iterator; + STABLE_VECTOR_CHECK_INVARIANT; + if(n > this->size()) + this->insert(this->cend(), default_init_iterator(n - this->size()), default_init_iterator()); else if(n < this->size()) this->erase(this->cbegin() + n, this->cend()); } diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 17aafc2..6ca0f4f 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -138,7 +138,7 @@ public: //! @pre count <= capacity() //! - //! @brief Constructs a static_vector containing count default constructed Values. + //! @brief Constructs a static_vector containing count value initialized values. //! //! @param count The number of values which will be contained in the container. //! @@ -151,6 +151,24 @@ public: : base_t(count) {} + //! @pre count <= capacity() + //! + //! @brief Constructs a static_vector containing count value initialized 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). + //! + //! @par Note + //! Non-standard extension + static_vector(size_type count, default_init_t) + : base_t(count, default_init_t()) + {} + //! @pre count <= capacity() //! //! @brief Constructs a static_vector containing count copies of value. @@ -358,7 +376,7 @@ public: //! @pre count <= capacity() //! //! @brief Inserts or erases elements at the end such that - //! the size becomes count. New elements are default constructed. + //! the size becomes count. New elements are value initialized. //! //! @param count The number of elements which will be stored in the container. //! @@ -369,6 +387,23 @@ public: //! Linear O(N). void resize(size_type count); + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are default initialized. + //! + //! @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). + //! + //! @par Note + //! Non-standard extension + void resize(size_type count, default_init_t); + //! @pre count <= capacity() //! //! @brief Inserts or erases elements at the end such that diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 197bb85..e006326 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -937,7 +937,7 @@ class basic_string } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! //! Throws: If memory allocation throws //! diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 97a1ceb..eabcab9 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -293,18 +293,26 @@ struct vector_alloc_holder template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) : Allocator(boost::forward(a)) + , m_start() , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this + , m_capacity() { - m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first; + if(initial_size){ + m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first; + } } //Constructor, does not throw explicit vector_alloc_holder(size_type initial_size) : Allocator() + , m_start() , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this + , m_capacity() { - m_start = this->allocation_command - (allocate_new, initial_size, initial_size, m_capacity, m_start).first; + if(initial_size){ + m_start = this->allocation_command + (allocate_new, initial_size, initial_size, m_capacity, m_start).first; + } } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT @@ -319,8 +327,10 @@ struct vector_alloc_holder void first_allocation(size_type cap) { - m_start = this->allocation_command - (allocate_new, cap, cap, m_capacity, m_start).first; + if(cap){ + m_start = this->allocation_command + (allocate_new, cap, cap, m_capacity, m_start).first; + } } void first_allocation_same_allocator_type(size_type cap) @@ -417,16 +427,18 @@ struct vector_alloc_holder explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) : Allocator(boost::forward(a)) - , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this + , m_size(initial_size) //Size is initialized here... { + //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->first_allocation(initial_size); } //Constructor, does not throw explicit vector_alloc_holder(size_type initial_size) : Allocator() - , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this + , m_size(initial_size) //Size is initialized here... { + //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->first_allocation(initial_size); } @@ -611,7 +623,7 @@ class vector {} //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts n default contructed values. + //! and inserts n value initialized values. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's default constructor throws. @@ -620,7 +632,24 @@ class vector explicit vector(size_type n) : m_holder(n) { - boost::container::uninitialized_default_alloc_n(this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); + boost::container::uninitialized_value_init_alloc_n + (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); + } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor or allocation + //! throws or T's default constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + explicit vector(size_type n, default_init_t) + : m_holder(n) + { + boost::container::uninitialized_default_init_alloc_n + (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector @@ -1030,9 +1059,9 @@ class vector { return allocator_traits_type::max_size(this->m_holder.alloc()); } //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! the size becomes n. New elements are value initialized. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: If memory allocation throws, or T's constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) @@ -1044,7 +1073,29 @@ class vector } else{ const size_type n = new_size - this->size(); - container_detail::insert_default_constructed_n_proxy proxy(this->m_holder.alloc()); + container_detail::insert_value_initialized_n_proxy proxy(this->m_holder.alloc()); + this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are value initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + //! + //! Note: Non-standard extension + void resize(size_type new_size, default_init_t) + { + const size_type sz = this->size(); + if (new_size < sz){ + //Destroy last elements + this->priv_destroy_last_n(sz - new_size); + } + else{ + const size_type n = new_size - this->size(); + container_detail::insert_default_initialized_n_proxy proxy(this->m_holder.alloc()); this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } diff --git a/proj/vc7ide/bench_set.vcproj b/proj/vc7ide/bench_set.vcproj new file mode 100644 index 0000000..327e6fe --- /dev/null +++ b/proj/vc7ide/bench_set.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 082bf1d..0953f18 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -67,6 +67,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_static_vector", "benc ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set", "bench_set.vcproj", "{5E1C1C23-26A9-4FE5-A24E-DA735271C32B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -137,12 +141,14 @@ Global {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 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Release.ActiveCfg = Release|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.ActiveCfg = Debug|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.Build.0 = Debug|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Release.ActiveCfg = Release|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Debug.ActiveCfg = Debug|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Debug.Build.0 = Debug|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Release.ActiveCfg = Release|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 185a5c0..8841324 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -337,6 +337,9 @@ + + diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp index 3161884..119ec72 100644 --- a/test/allocator_traits_test.cpp +++ b/test/allocator_traits_test.cpp @@ -25,6 +25,12 @@ class SimpleAllocator public: typedef T value_type; + template + SimpleAllocator(SimpleAllocator) + : 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 + 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; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 2889423..f483fd6 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -332,6 +332,10 @@ int main () return 1; if(test::vector_test()) return 1; + if(!test::default_init_test< deque > >()){ + 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); diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index 459aace..6390d7e 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -66,6 +66,36 @@ void recursive_vector_test()//Test for recursive types } } +bool default_init_test()//Test for default initialization +{ + typedef stable_vector > svector_t; + + const std::size_t Capacity = 100; + + { + test::default_init_allocator::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(i)) + return false; + } + } + { + test::default_init_allocator::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(i+100)) + return false; + } + } + return true; +} + int main() { recursive_vector_test(); @@ -102,6 +132,11 @@ int main() if(test::vector_test()) return 1; + if(!test::default_init_test< stable_vector > >()){ + 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, Options>()) diff --git a/test/static_vector_test.cpp b/test/static_vector_test.cpp index 21efeb7..30914af 100644 --- a/test/static_vector_test.cpp +++ b/test/static_vector_test.cpp @@ -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 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(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(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(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(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(50)); test_sv_elem(movable_and_copyable_int(50)); + + BOOST_TEST(default_init_test() == true); + return boost::report_errors(); } diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 3b34c92..80417c3 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -151,6 +151,10 @@ int main() return 1; if(test_expand_bwd()) return 1; + if(!test::default_init_test< vector > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } MyEnumVector v; Test t; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index b1a4fb5..3dc2401 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -31,12 +31,130 @@ #include #include #include +#include #include "insert_test.hpp" namespace boost{ namespace container { namespace test{ +// +template +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 +unsigned char default_init_allocator_base::s_pattern = 0u; + +template +bool default_init_allocator_base::s_ascending = true; + +template +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 + default_init_allocator(default_init_allocator) + {} + + T* allocate(std::size_t n) + { + //Initialize memory to a pattern + T *const p = ::new T[n]; + unsigned char *puc_raw = reinterpret_cast(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(s_pattern++); + } + } + else{ + for(std::size_t i = 0; i != max; ++i){ + puc_raw[i] = static_cast(s_pattern--); + } + } + return p; + } + + void deallocate(T *p, std::size_t) + { delete[] p; } +}; + +template +inline bool check_ascending_byte_pattern(const T&t) +{ + const unsigned char *pch = &reinterpret_cast(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 +inline bool check_descending_byte_pattern(const T&t) +{ + const unsigned char *pch = &reinterpret_cast(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 +bool default_init_test()//Test for default initialization +{ + const std::size_t Capacity = 100; + + { + test::default_init_allocator::reset_pattern(0); + test::default_init_allocator::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::reset_pattern(100); + test::default_init_allocator::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 bool vector_copyable_only(V1 *, V2 *, boost::container::container_detail::false_type) { @@ -100,7 +218,7 @@ template int vector_test() { typedef std::vector MyStdVector; - typedef typename MyBoostVector::value_type IntType; + typedef typename MyBoostVector::value_type IntType; const int max = 100; if(!test_range_insertion()){