From d55108b720c6ac9b42125ba19cc02f504fd26dda Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 15 Dec 2012 16:30:57 +0000 Subject: [PATCH] Added ctor and modified assign to static_vector. static_vector(Iter, Iter), assign(Iter, Iter) + separated version for RandomIterators. Private helper methods now are able to take arbitrary type (Iterator, Value). [SVN r81971] --- .../extensions/index/static_vector.hpp | 304 ++++++++++++------ test/static_vector.cpp | 59 +++- 2 files changed, 265 insertions(+), 98 deletions(-) diff --git a/include/boost/geometry/extensions/index/static_vector.hpp b/include/boost/geometry/extensions/index/static_vector.hpp index ae5a48862..cb04e6cde 100644 --- a/include/boost/geometry/extensions/index/static_vector.hpp +++ b/include/boost/geometry/extensions/index/static_vector.hpp @@ -7,10 +7,16 @@ // http://www.boost.org/LICENSE_1_0.txt) #include -#include + #include #include +#include +#include +#include +#include + +#include #include #include #include @@ -55,32 +61,38 @@ public: explicit static_vector(size_type s) : m_size(0) { - resize(s); // may throw + resize(s); // may throw } // strong static_vector(size_type s, value_type const& value) : m_size(0) { - resize(s, value); // may throw + resize(s, value); // may throw } // strong static_vector(static_vector const& other) + : m_size(other.m_size) { - //BOOST_ASSERT_MSG(other.m_size <= Capacity, "capacity too small"); + //BOOST_ASSERT_MSG(other.m_size <= Capacity, "size can't exceed the capacity"); + //if ( Capacity <= other.m_size ) throw std::bad_alloc(); - this->uninitialized_copy(other.ptr(0), other.ptr(other.m_size), this->ptr(0), - boost::has_trivial_copy()); - m_size = other.m_size; + this->uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + // strong + template + static_vector(Iterator first, Iterator last) + : m_size(0) + { + assign(first, last); // may throw } // basic static_vector & operator=(static_vector const& other) { - //BOOST_ASSERT_MSG(other.m_size <= Capacity, "capacity too small"); - - assign(other.ptr(0), other.ptr(other.m_size)); + assign(other.begin(), other.end()); // may throw return *this; } @@ -88,8 +100,7 @@ public: // nothrow ~static_vector() { - this->destroy(this->ptr(0), this->ptr(m_size), - boost::has_trivial_destructor()); + this->destroy(this->begin(), this->end()); } // strong @@ -97,17 +108,15 @@ public: { if ( s < m_size ) { - this->destroy(this->ptr(s), this->ptr(m_size), - boost::has_trivial_destructor()); - m_size = s; + this->destroy(this->begin() + s, this->end()); } else { BOOST_ASSERT_MSG(s <= Capacity, "size can't exceed the capacity"); - this->construct(this->ptr(m_size), this->ptr(s), - boost::has_trivial_constructor()); // may throw - m_size = s; + //if ( Capacity <= s ) throw std::bad_alloc(); + this->construct(this->ptr(m_size), this->ptr(s)); // may throw } + m_size = s; // update end } // strong @@ -115,74 +124,55 @@ public: { if ( s < m_size ) { - this->destroy(this->ptr(s), this->ptr(m_size), - boost::has_trivial_destructor()); - m_size = s; + this->destroy(this->begin() + s, this->end()); } else { BOOST_ASSERT_MSG(s <= Capacity, "size can't exceed the capacity"); - std::uninitialized_fill(this->ptr(m_size), this->ptr(s), value); // may throw - m_size = s; + //if ( Capacity <= s ) throw std::bad_alloc(); + std::uninitialized_fill(this->ptr(m_size), this->ptr(s), value); // may throw } + m_size = s; // update end } // nothrow void reserve(size_type BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(s)) { - BOOST_ASSERT_MSG(s <= Capacity, "max capacity reached"); + BOOST_ASSERT_MSG(s <= Capacity, "size can't exceed the capacity"); + //if ( Capacity <= s ) throw std::bad_alloc(); } // strong + //template void push_back(Value const& value) { - BOOST_ASSERT_MSG(m_size < Capacity, "max capacity reached"); - this->uninitialized_copy(this->ptr(m_size), value, - boost::has_trivial_copy()); // may throw - ++m_size; + BOOST_ASSERT_MSG(m_size < Capacity, "size can't exceed the capacity"); + //if ( Capacity <= m_size ) throw std::bad_alloc(); + this->uninitialized_copy(value, this->end()); // may throw + ++m_size; // update end } // nothrow void pop_back() { BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); - --m_size; - this->destroy(this->ptr(m_size), boost::has_trivial_destructor()); + --m_size; // update end + this->destroy(this->ptr(m_size)); } // basic - void assign(const value_type * first, const value_type * last) + template + void assign(Iterator first, Iterator last) { - size_type s = std::distance(first, last); - - BOOST_ASSERT_MSG(s <= Capacity, "max capacity reached"); - - if ( m_size <= s ) - { - this->copy(first, first + m_size, this->ptr(0), - boost::has_trivial_assign()); // may throw - - this->uninitialized_copy(first + m_size, last, this->ptr(m_size), - boost::has_trivial_copy()); // may throw - m_size = s; - } - else - { - this->copy(first, last, this->ptr(0), - boost::has_trivial_assign()); // may throw - - this->destroy(this->ptr(s), this->ptr(m_size), - boost::has_trivial_destructor()); - m_size = s; - } + typedef typename boost::iterator_traversal::type traversal; + assign_dispatch(first, last, traversal()); // may throw } // nothrow void clear() { - this->destroy(this->ptr(0), this->ptr(m_size), - boost::has_trivial_destructor()); - m_size = 0; + this->destroy(this->ptr(0), this->ptr(m_size)); + m_size = 0; // update end } // strong @@ -219,28 +209,28 @@ public: Value & front() { BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); - return *(this->ptr(0)); + return *(this->begin()); } // nothrow Value const& front() const { BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); - return *(this->ptr(0)); + return *(this->begin()); } // nothrow Value & back() { BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); - return *(this->ptr(m_size - 1)); + return *(this->end() - 1); } // nothrow Value const& back() const { BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); - return *(this->ptr(m_size - 1)); + return *(this->end() - 1); } // nothrow @@ -248,9 +238,9 @@ public: const Value * data() const { return this->ptr(0); } // nothrow - iterator begin() { return this->ptr(0); } - const_iterator begin() const { return this->ptr(0); } - const_iterator cbegin() const { return this->ptr(0); } + iterator begin() { return this->ptr(); } + const_iterator begin() const { return this->ptr(); } + const_iterator cbegin() const { return this->ptr(); } iterator end() { return this->ptr(m_size); } const_iterator end() const { return this->ptr(m_size); } const_iterator cend() const { return this->ptr(m_size); } @@ -269,78 +259,202 @@ public: bool empty() const { return 0 == m_size; } private: - void copy(const value_type * first, const value_type * last, value_type * dst, - boost::true_type const& /*has_trivial_assign*/) + + // assign + + template + void assign_dispatch(Iterator first, Iterator last, boost::random_access_traversal_tag const&) + { + size_type s = std::distance(first, last); + + BOOST_ASSERT_MSG(s <= Capacity, "size can't exceed the capacity"); + //if ( Capacity <= m_size ) throw std::bad_alloc(); + + if ( m_size <= s ) + { + this->copy(first, first + m_size, this->begin()); // may throw + this->uninitialized_copy(first + m_size, last, this->ptr(m_size)); // may throw + } + else + { + this->copy(first, last, this->begin()); // may throw + this->destroy(this->ptr(s), this->ptr(m_size)); + } + m_size = s; // update end + } + + template + void assign_dispatch(Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + size_t s = 0; + iterator it = this->begin(); + + for ( ; it != this->end() && first != last ; ++it, ++first, ++s ) + *it = *first; // may throw + + this->destroy(it, this->end()); + + try + { + for ( ; first != last ; ++it, ++first, ++s ) + this->uninitialized_copy(*first, it); // may throw + m_size = s; // update end + } + catch(...) + { + this->destroy(this->begin() + m_size, it); + throw; + } + } + + // copy + + template + void copy(Iterator first, Iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_assign, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->copy_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void copy_dispatch(const value_type * first, const value_type * last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) { ::memcpy(dst, first, sizeof(value_type) * std::distance(first, last)); } - void copy(const value_type * first, const value_type * last, value_type * dst, - boost::false_type const& /*has_trivial_assign*/) + template + void copy_dispatch(Iterator first, Iterator last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) { - std::copy(first, last, dst); // may throw + std::copy(first, last, dst); // may throw } - void uninitialized_copy(const value_type * first, const value_type * last, value_type * dst, - boost::true_type const& /*has_trivial_copy*/) + // uninitialized_copy + + template + void uninitialized_copy(Iterator first, Iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_copy, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void uninitialized_copy_dispatch(const value_type * first, const value_type * last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) { ::memcpy(dst, first, sizeof(value_type) * std::distance(first, last)); } - void uninitialized_copy(const value_type * first, const value_type * last, value_type * dst, - boost::false_type const& /*has_trivial_copy*/) + template + void uninitialized_copy_dispatch(Iterator first, Iterator last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) { - std::uninitialized_copy(first, last, dst); // may throw + std::uninitialized_copy(first, last, dst); // may throw } - void uninitialized_copy(value_type * ptr, value_type const& v, - boost::true_type const& /*has_trivial_copy*/) + // uninitialized_copy + + template + void uninitialized_copy(Value const& v, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_copy, + is_same + >::type + use_memcpy; + + uninitialized_copy_dispatch(v, dst, use_memcpy()); // may throw + } + + void uninitialized_copy_dispatch(value_type const& v, value_type * ptr, + boost::mpl::bool_ const& /*use_memcpy*/) { ::memcpy(ptr, &v, sizeof(value_type)); } - void uninitialized_copy(value_type * ptr, value_type const& v, - boost::false_type const& /*has_trivial_copy*/) + template + void uninitialized_copy_dispatch(Value const& v, value_type * ptr, + boost::mpl::bool_ const& /*use_memcpy*/) { new (ptr) value_type(v); // may throw } - void destroy(const value_type * /*first*/, const value_type * /*last*/, - boost::true_type const& /*has_trivial_destructor*/) + // destroy + + void destroy(iterator first, iterator last) + { + this->destroy_dispatch(first, last, has_trivial_destructor()); + } + + void destroy_dispatch(value_type * /*first*/, value_type * /*last*/, + boost::true_type const& /*has_trivial_destructor*/) {} - void destroy(const value_type * first, const value_type * last, - boost::false_type const& /*has_trivial_destructor*/) + void destroy_dispatch(value_type * first, value_type * last, + boost::false_type const& /*has_trivial_destructor*/) { for ( ; first != last ; ++first ) first->~value_type(); } - void destroy(const value_type * /*ptr*/, - boost::true_type const& /*has_trivial_destructor*/) + // destroy + + void destroy(iterator it) + { + this->destroy_dispatch(it, has_trivial_destructor()); + } + + void destroy_dispatch(value_type * /*ptr*/, + boost::true_type const& /*has_trivial_destructor*/) {} - void destroy(const value_type * ptr, boost::false_type const& /*has_trivial_destructor*/) + void destroy_dispatch(value_type * ptr, + boost::false_type const& /*has_trivial_destructor*/) { ptr->~value_type(); } - void construct(value_type * /*first*/, value_type * /*last*/, - boost::true_type const& /*has_trivial_constructor*/) + // construct + + void construct(iterator first, iterator last) + { + this->construct_dispatch(first, last, has_trivial_constructor()); // may throw + } + + void construct_dispatch(value_type * /*first*/, value_type * /*last*/, + boost::true_type const& /*has_trivial_constructor*/) {} - void construct(value_type * first, value_type * last, - boost::false_type const& /*has_trivial_constructor*/) + void construct_dispatch(value_type * first, value_type * last, + boost::false_type const& /*has_trivial_constructor*/) { value_type * it = first; try { for ( ; it != last ; ++it ) - new (it) value_type(); // may throw + new (it) value_type(); // may throw } catch(...) { - this->destroy(first, it, boost::has_trivial_destructor()); + this->destroy(first, it); throw; } } @@ -355,6 +469,16 @@ private: return (reinterpret_cast(m_storage.address()) + i); } + Value * ptr() + { + return (reinterpret_cast(m_storage.address())); + } + + const Value * ptr() const + { + return (reinterpret_cast(m_storage.address())); + } + boost::aligned_storage::value> m_storage; size_type m_size; }; diff --git a/test/static_vector.cpp b/test/static_vector.cpp index b99fbaa64..4e123ddee 100644 --- a/test/static_vector.cpp +++ b/test/static_vector.cpp @@ -195,35 +195,78 @@ void test_pop_back_nd() } } +template +void test_compare_ranges(It1 first1, It1 last1, It2 first2, It2 last2) +{ + BOOST_CHECK(std::distance(first1, last1) == std::distance(first2, last2)); + for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2 ) + BOOST_CHECK(*first1 == *first2); +} + template void test_copy_and_assign_nd() { static_vector s; + std::vector v; + std::list l; for ( size_t i = 0 ; i < N ; ++i ) - s.push_back(i); - + { + s.push_back(i); + v.push_back(i); + l.push_back(i); + } + // copy ctor { static_vector s1(s); BOOST_CHECK(s.size() == s1.size()); - for ( size_t i = 0 ; i < N ; ++i ) - BOOST_CHECK(s[i] == s1[i]) ; + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); } + // copy assignment { static_vector s1; BOOST_CHECK(0 == s1.size()); s1 = s; BOOST_CHECK(s.size() == s1.size()); - for ( size_t i = 0 ; i < N ; ++i ) - BOOST_CHECK(s[i] == s1[i]) ; + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); } + // ctor(Iter, Iter) + { + static_vector s1(s.begin(), s.end()); + BOOST_CHECK(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + { + static_vector s1(v.begin(), v.end()); + BOOST_CHECK(v.size() == s1.size()); + test_compare_ranges(v.begin(), v.end(), s1.begin(), s1.end()); + } + { + static_vector s1(l.begin(), l.end()); + BOOST_CHECK(l.size() == s1.size()); + test_compare_ranges(l.begin(), l.end(), s1.begin(), s1.end()); + } + // assign(Iter, Iter) { static_vector s1; BOOST_CHECK(0 == s1.size()); s1.assign(s.begin(), s.end()); BOOST_CHECK(s.size() == s1.size()); - for ( size_t i = 0 ; i < N ; ++i ) - BOOST_CHECK(s[i] == s1[i]) ; + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + { + static_vector s1; + BOOST_CHECK(0 == s1.size()); + s1.assign(v.begin(), v.end()); + BOOST_CHECK(v.size() == s1.size()); + test_compare_ranges(v.begin(), v.end(), s1.begin(), s1.end()); + } + { + static_vector s1; + BOOST_CHECK(0 == s1.size()); + s1.assign(l.begin(), l.end()); + BOOST_CHECK(l.size() == s1.size()); + test_compare_ranges(l.begin(), l.end(), s1.begin(), s1.end()); } }