diff --git a/doc/container.qbk b/doc/container.qbk index 8a7616b..7ca7cfc 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1216,6 +1216,8 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_60_00 Boost 1.60 Release] * Implemented [link container.extended_functionality.polymorphic_memory_resources Polymorphic Memory Resources]. +* Add more BOOST_ASSERT checks to test preconditions in some operations (like `pop_back`, `pop_front`, `back`, `front`, etc.) +* Added C++11 `back`/`front` operations to [classref boost::container::basic_string basic_string]. * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/11627 Trac #11627: ['"small_vector::swap() appears to be broken"]]. * [@https://svn.boost.org/trac/boost/ticket/11628 Trac #11628: ['"small_vector iterates over elements in destructor"]]. diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index bdfecc1..14ba6da 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2015. 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) // @@ -1140,7 +1140,10 @@ class deque : protected deque_base //! //! Complexity: Constant. reference front() BOOST_NOEXCEPT_OR_NOTHROW - { return *this->members_.m_start; } + { + BOOST_ASSERT(!this->empty()); + return *this->members_.m_start; + } //! Requires: !empty() //! @@ -1151,7 +1154,10 @@ class deque : protected deque_base //! //! Complexity: Constant. const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->members_.m_start; } + { + BOOST_ASSERT(!this->empty()); + return *this->members_.m_start; + } //! Requires: !empty() //! @@ -1162,7 +1168,10 @@ class deque : protected deque_base //! //! Complexity: Constant. reference back() BOOST_NOEXCEPT_OR_NOTHROW - { return *(end()-1); } + { + BOOST_ASSERT(!this->empty()); + return *(end()-1); + } //! Requires: !empty() //! @@ -1173,7 +1182,10 @@ class deque : protected deque_base //! //! Complexity: Constant. const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW - { return *(cend()-1); } + { + BOOST_ASSERT(!this->empty()); + return *(cend()-1); + } //! Requires: size() > n. //! @@ -1184,7 +1196,10 @@ class deque : protected deque_base //! //! Complexity: Constant. reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_start[difference_type(n)]; } + { + BOOST_ASSERT(this->size() > n); + return this->members_.m_start[difference_type(n)]; + } //! Requires: size() > n. //! @@ -1195,7 +1210,10 @@ class deque : protected deque_base //! //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_start[difference_type(n)]; } + { + BOOST_ASSERT(this->size() > n); + return this->members_.m_start[difference_type(n)]; + } //! Requires: size() >= n. //! @@ -1243,7 +1261,10 @@ class deque : protected deque_base //! //! Note: Non-standard extension size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_index_of(p); } + { + //Range checked priv_index_of + return this->priv_index_of(p); + } //! Requires: begin() <= p <= end(). //! @@ -1256,7 +1277,10 @@ class deque : protected deque_base //! //! Note: Non-standard extension size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_index_of(p); } + { + //Range checked priv_index_of + return this->priv_index_of(p); + } //! Requires: size() > n. //! @@ -1267,7 +1291,10 @@ class deque : protected deque_base //! //! Complexity: Constant. reference at(size_type n) - { this->priv_range_check(n); return (*this)[n]; } + { + this->priv_throw_if_out_of_range(n); + return (*this)[n]; + } //! Requires: size() > n. //! @@ -1278,7 +1305,10 @@ class deque : protected deque_base //! //! Complexity: Constant. const_reference at(size_type n) const - { this->priv_range_check(n); return (*this)[n]; } + { + this->priv_throw_if_out_of_range(n); + return (*this)[n]; + } ////////////////////////////////////////////// // @@ -1344,6 +1374,7 @@ class deque : protected deque_base template iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); if(p == this->cbegin()){ this->emplace_front(boost::forward(args)...); return this->begin(); @@ -1394,6 +1425,7 @@ class deque : protected deque_base BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ + BOOST_ASSERT(this->priv_in_range_or_end(p));\ if(p == this->cbegin()){\ this->emplace_front(BOOST_MOVE_FWD##N);\ return this->begin();\ @@ -1494,6 +1526,7 @@ class deque : protected deque_base //! Complexity: Linear to n. iterator insert(const_iterator pos, size_type n, const value_type& x) { + //Range check of p is done by insert() typedef constant_iterator c_it; return this->insert(pos, c_it(x, n), c_it()); } @@ -1519,6 +1552,7 @@ class deque : protected deque_base #endif ) { + BOOST_ASSERT(this->priv_in_range_or_end(pos)); size_type n = 0; iterator it(pos.unconst()); for(;first != last; ++first, ++n){ @@ -1541,7 +1575,10 @@ class deque : protected deque_base //! //! Complexity: Linear to distance [il.begin(), il.end()). iterator insert(const_iterator pos, std::initializer_list il) - { return insert(pos, il.begin(), il.end()); } + { + //Range check os pos is done in insert() + return insert(pos, il.begin(), il.end()); + } #endif #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1556,6 +1593,7 @@ class deque : protected deque_base #endif ) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); container_detail::insert_range_proxy proxy(first); return priv_insert_aux_impl(p, boost::container::iterator_distance(first, last), proxy); } @@ -1568,6 +1606,7 @@ class deque : protected deque_base //! Complexity: Constant time. void pop_front() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(!this->empty()); if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { allocator_traits_type::destroy ( this->alloc() @@ -1586,6 +1625,7 @@ class deque : protected deque_base //! Complexity: Constant time. void pop_back() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(!this->empty()); if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { --this->members_.m_finish.m_cur; allocator_traits_type::destroy @@ -1607,6 +1647,7 @@ class deque : protected deque_base //! Constant if pos is the first or the last element. iterator erase(const_iterator pos) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(this->priv_in_range(pos)); iterator next = pos.unconst(); ++next; size_type index = pos - this->members_.m_start; @@ -1631,6 +1672,9 @@ class deque : protected deque_base //! if(pos is near the beginning). iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(first <= last); + BOOST_ASSERT(first == last || this->priv_in_range(first)); + BOOST_ASSERT(first == last || this->priv_in_range_or_end(last)); if (first == this->members_.m_start && last == this->members_.m_finish) { this->clear(); return this->members_.m_finish; @@ -1764,12 +1808,26 @@ class deque : protected deque_base } } - void priv_range_check(size_type n) const - { if (n >= this->size()) throw_out_of_range("deque::at out of range"); } + void priv_throw_if_out_of_range(size_type n) const + { + if (n >= this->size()) + throw_out_of_range("deque::at out of range"); + } + + bool priv_in_range(const_iterator pos) const + { + return (this->begin() <= pos) && (pos < this->end()); + } + + bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } template iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); if (p == cbegin()){ this->push_front(::boost::forward(x)); return begin(); diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index f274211..4c48c8b 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2015. 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) // @@ -376,35 +376,39 @@ class flat_tree return i; } - iterator insert_unique(const_iterator pos, const value_type& val) + iterator insert_unique(const_iterator hint, const value_type& val) { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); std::pair ret; insert_commit_data data; - return this->priv_insert_unique_prepare(pos, val, data) + return this->priv_insert_unique_prepare(hint, val, data) ? this->priv_insert_commit(data, val) : iterator(vector_iterator_get_ptr(data.position)); } - iterator insert_unique(const_iterator pos, BOOST_RV_REF(value_type) val) + iterator insert_unique(const_iterator hint, BOOST_RV_REF(value_type) val) { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); std::pair ret; insert_commit_data data; - return this->priv_insert_unique_prepare(pos, val, data) + return this->priv_insert_unique_prepare(hint, val, data) ? this->priv_insert_commit(data, boost::move(val)) : iterator(vector_iterator_get_ptr(data.position)); } - iterator insert_equal(const_iterator pos, const value_type& val) + iterator insert_equal(const_iterator hint, const value_type& val) { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); insert_commit_data data; - this->priv_insert_equal_prepare(pos, val, data); + this->priv_insert_equal_prepare(hint, val, data); return this->priv_insert_commit(data, val); } - iterator insert_equal(const_iterator pos, BOOST_RV_REF(value_type) mval) + iterator insert_equal(const_iterator hint, BOOST_RV_REF(value_type) mval) { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); insert_commit_data data; - this->priv_insert_equal_prepare(pos, mval, data); + this->priv_insert_equal_prepare(hint, mval, data); return this->priv_insert_commit(data, boost::move(mval)); } @@ -524,6 +528,7 @@ class flat_tree template iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args) { + //hint checked in insert_unique typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); stored_allocator_type &a = this->get_stored_allocator(); @@ -546,6 +551,7 @@ class flat_tree template iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args) { + //hint checked in insert_equal typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); stored_allocator_type &a = this->get_stored_allocator(); @@ -732,6 +738,12 @@ class flat_tree { x.swap(y); } private: + + bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } + struct insert_commit_data { const_iterator position; diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index c902029..575565c 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2015. 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) // @@ -811,6 +811,7 @@ class tree std::pair insert_unique_check (const_iterator hint, const key_type& key, insert_commit_data &data) { + BOOST_ASSERT((priv_is_linked)(hint)); std::pair ret = this->icont().insert_unique_check(hint.get(), key, KeyNodeCompare(value_comp()), data); return std::pair(iterator(ret.first), ret.second); @@ -861,6 +862,15 @@ class tree private: + bool priv_is_linked(const_iterator const position) const + { + iiterator const cur(position.get()); + return cur == this->icont().end() || + cur == this->icont().root() || + iiterator(cur).go_parent().go_left() == cur || + iiterator(cur).go_parent().go_right() == cur; + } + template void push_back_impl(BOOST_FWD_REF(MovableConvertible) v) { @@ -888,6 +898,7 @@ class tree iterator emplace_unique_hint_impl(const_iterator hint, NodePtr p) { + BOOST_ASSERT((priv_is_linked)(hint)); value_type &v = p->get_data(); insert_commit_data data; std::pair ret = @@ -924,6 +935,7 @@ class tree template iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args) { + BOOST_ASSERT((priv_is_linked)(hint)); NodePtr tmp(AllocHolder::create_node(boost::forward(args)...)); scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); iterator ret(this->icont().insert_equal(hint.get(), *tmp)); @@ -955,6 +967,7 @@ class tree BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace_hint_equal(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ + BOOST_ASSERT((priv_is_linked)(hint));\ NodePtr tmp(AllocHolder::create_node(BOOST_MOVE_FWD##N));\ scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc());\ iterator ret(this->icont().insert_equal(hint.get(), *tmp));\ @@ -969,6 +982,7 @@ class tree iterator insert_unique(const_iterator hint, const value_type& v) { + BOOST_ASSERT((priv_is_linked)(hint)); insert_commit_data data; std::pair ret = this->insert_unique_check(hint, KeyOfValue()(v), data); @@ -980,6 +994,7 @@ class tree template iterator insert_unique(const_iterator hint, BOOST_FWD_REF(MovableConvertible) v) { + BOOST_ASSERT((priv_is_linked)(hint)); insert_commit_data data; std::pair ret = this->insert_unique_check(hint, KeyOfValue()(v), data); @@ -1016,6 +1031,7 @@ class tree iterator insert_equal(const_iterator hint, const value_type& v) { + BOOST_ASSERT((priv_is_linked)(hint)); NodePtr tmp(AllocHolder::create_node(v)); scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); iterator ret(this->icont().insert_equal(hint.get(), *tmp)); @@ -1026,6 +1042,7 @@ class tree template iterator insert_equal(const_iterator hint, BOOST_FWD_REF(MovableConvertible) v) { + BOOST_ASSERT((priv_is_linked)(hint)); NodePtr tmp(AllocHolder::create_node(boost::forward(v))); scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); iterator ret(this->icont().insert_equal(hint.get(), *tmp)); @@ -1041,13 +1058,20 @@ class tree } iterator erase(const_iterator position) - { return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); } + { + BOOST_ASSERT(position != this->cend() && (priv_is_linked)(position)); + return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); + } size_type erase(const key_type& k) { return AllocHolder::erase_key(k, KeyNodeCompare(value_comp()), alloc_version()); } iterator erase(const_iterator first, const_iterator last) - { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + { + BOOST_ASSERT(first == last || (first != this->cend() && (priv_is_linked)(first))); + BOOST_ASSERT(first == last || (priv_is_linked)(last)); + return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); + } void clear() { AllocHolder::clear(alloc_version()); } diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 5135eae..8236ff7 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2015. 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) // @@ -651,7 +651,10 @@ class list //! //! Complexity: Constant. reference front() BOOST_NOEXCEPT_OR_NOTHROW - { return *this->begin(); } + { + BOOST_ASSERT(!this->empty()); + return *this->begin(); + } //! Requires: !empty() //! @@ -662,7 +665,10 @@ class list //! //! Complexity: Constant. const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->begin(); } + { + BOOST_ASSERT(!this->empty()); + return *this->begin(); + } //! Requires: !empty() //! @@ -673,7 +679,10 @@ class list //! //! Complexity: Constant. reference back() BOOST_NOEXCEPT_OR_NOTHROW - { return *(--this->end()); } + { + BOOST_ASSERT(!this->empty()); + return *(--this->end()); + } //! Requires: !empty() //! @@ -684,7 +693,10 @@ class list //! //! Complexity: Constant. const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW - { return *(--this->end()); } + { + BOOST_ASSERT(!this->empty()); + return *(--this->end()); + } ////////////////////////////////////////////// // @@ -724,10 +736,11 @@ class list //! //! Complexity: Constant template - iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args) + iterator emplace(const_iterator position, BOOST_FWD_REF(Args)... args) { + BOOST_ASSERT((priv_is_linked)(position)); NodePtr pnode(AllocHolder::create_node(boost::forward(args)...)); - return iterator(this->icont().insert(p.get(), *pnode)); + return iterator(this->icont().insert(position.get(), *pnode)); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -742,10 +755,11 @@ class list { this->emplace(this->cbegin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ + BOOST_ASSERT(position == this->cend() || (--(++position) == position) );\ NodePtr pnode (AllocHolder::create_node(BOOST_MOVE_FWD##N));\ - return iterator(this->icont().insert(p.get(), *pnode));\ + return iterator(this->icont().insert(position.get(), *pnode));\ }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_LIST_EMPLACE_CODE) @@ -828,10 +842,11 @@ class list //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - iterator insert(const_iterator p, size_type n, const T& x) + iterator insert(const_iterator position, size_type n, const T& x) { + //range check is done by insert typedef constant_iterator cvalue_iterator; - return this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); + return this->insert(position, cvalue_iterator(x, n), cvalue_iterator()); } //! Requires: p must be a valid iterator of *this. @@ -856,6 +871,7 @@ class list #endif ) { + BOOST_ASSERT((priv_is_linked)(p)); const typename Icont::iterator ipos(p.get()); iterator ret_it(ipos); if(first != last){ @@ -870,7 +886,7 @@ class list #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template - iterator insert(const_iterator p, FwdIt first, FwdIt last + iterator insert(const_iterator position, FwdIt first, FwdIt last , typename container_detail::enable_if_c < !container_detail::is_convertible::value && !(container_detail::is_input_iterator::value @@ -879,9 +895,10 @@ class list >::type * = 0 ) { + BOOST_ASSERT((priv_is_linked)(position)); //Optimized allocation and construction - insertion_functor func(this->icont(), p.get()); - iterator before_p(p.get()); + insertion_functor func(this->icont(), position.get()); + iterator before_p(position.get()); --before_p; this->allocate_many_and_construct(first, boost::container::iterator_distance(first, last), func); return ++before_p; @@ -900,7 +917,10 @@ class list //! //! Complexity: Linear to distance [il.begin(), il.end()). iterator insert(const_iterator p, std::initializer_list il) - { return insert(p, il.begin(), il.end()); } + { + //position range check is done by insert() + return insert(p, il.begin(), il.end()); + } #endif //! Effects: Removes the first element from the list. @@ -909,7 +929,10 @@ class list //! //! Complexity: Amortized constant time. void pop_front() BOOST_NOEXCEPT_OR_NOTHROW - { this->erase(this->cbegin()); } + { + BOOST_ASSERT(!this->empty()); + this->erase(this->cbegin()); + } //! Effects: Removes the last element from the list. //! @@ -917,7 +940,11 @@ class list //! //! Complexity: Amortized constant time. void pop_back() BOOST_NOEXCEPT_OR_NOTHROW - { const_iterator tmp = this->cend(); this->erase(--tmp); } + { + BOOST_ASSERT(!this->empty()); + const_iterator tmp = this->cend(); + this->erase(--tmp); + } //! Requires: p must be a valid iterator of *this. //! @@ -927,7 +954,10 @@ class list //! //! Complexity: Amortized constant time. iterator erase(const_iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } + { + BOOST_ASSERT(p != this->cend() && (priv_is_linked)(p)); + return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); + } //! Requires: first and last must be valid iterator to elements in *this. //! @@ -937,7 +967,11 @@ class list //! //! Complexity: Linear to the distance between first and last. iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW - { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + { + BOOST_ASSERT(first == last || (first != this->cend() && (priv_is_linked)(first))); + BOOST_ASSERT(first == last || (priv_is_linked)(last)); + return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); + } //! Effects: Swaps the contents of *this and x. //! @@ -947,7 +981,12 @@ class list void swap(list& x) BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_swap::value || allocator_traits_type::is_always_equal::value) - { AllocHolder::swap(x); } + { + BOOST_ASSERT(allocator_traits_type::propagate_on_container_swap::value || + allocator_traits_type::is_always_equal::value || + this->get_stored_allocator() == x.get_stored_allocator()); + AllocHolder::swap(x); + } //! Effects: Erases all the elements of the list. //! @@ -977,6 +1016,7 @@ class list //! this list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, list& x) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT((priv_is_linked)(p)); BOOST_ASSERT(this != &x); BOOST_ASSERT(this->node_alloc() == x.node_alloc()); this->icont().splice(p.get(), x.icont()); @@ -995,7 +1035,10 @@ class list //! Note: Iterators of values obtained from list x now point to elements of //! this list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, BOOST_RV_REF(list) x) BOOST_NOEXCEPT_OR_NOTHROW - { this->splice(p, static_cast(x)); } + { + //Checks done in splice + this->splice(p, static_cast(x)); + } //! Requires: p must point to an element contained //! by this list. i must point to an element contained in list x. @@ -1013,7 +1056,7 @@ class list //! list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, list &x, const_iterator i) BOOST_NOEXCEPT_OR_NOTHROW { - //BOOST_ASSERT(this != &x); + BOOST_ASSERT((priv_is_linked)(p)); BOOST_ASSERT(this->node_alloc() == x.node_alloc()); this->icont().splice(p.get(), x.icont(), i.get()); } @@ -1033,7 +1076,11 @@ class list //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, BOOST_RV_REF(list) x, const_iterator i) BOOST_NOEXCEPT_OR_NOTHROW - { this->splice(p, static_cast(x), i); } + { + BOOST_ASSERT(this != &x); + //Additional checks done in splice() + this->splice(p, static_cast(x), i); + } //! Requires: p must point to an element contained //! by this list. first and last must point to elements contained in list x. @@ -1050,6 +1097,9 @@ class list //! list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, list &x, const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT((priv_is_linked)(p)); + BOOST_ASSERT(first == last || (first != x.cend() && x.priv_is_linked(first))); + BOOST_ASSERT(first == last || x.priv_is_linked(last)); BOOST_ASSERT(this->node_alloc() == x.node_alloc()); this->icont().splice(p.get(), x.icont(), first.get(), last.get()); } @@ -1068,7 +1118,11 @@ class list //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. void splice(const_iterator p, BOOST_RV_REF(list) x, const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW - { this->splice(p, static_cast(x), first, last); } + { + BOOST_ASSERT(this != &x); + //Additional checks done in splice() + this->splice(p, static_cast(x), first, last); + } //! Requires: p must point to an element contained //! by this list. first and last must point to elements contained in list x. @@ -1318,6 +1372,13 @@ class list #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + static bool priv_is_linked(const_iterator const position) + { + const_iterator cur(position); + //This list is circular including end nodes + return (--(++cur)) == position && (++(--cur)) == position; + } + bool priv_try_shrink(size_type new_size) { const size_type len = this->size(); @@ -1348,12 +1409,14 @@ class list iterator priv_insert(const_iterator p, const T &x) { + BOOST_ASSERT((priv_is_linked)(p)); NodePtr tmp = AllocHolder::create_node(x); return iterator(this->icont().insert(p.get(), *tmp)); } iterator priv_insert(const_iterator p, BOOST_RV_REF(T) x) { + BOOST_ASSERT((priv_is_linked)(p)); NodePtr tmp = AllocHolder::create_node(boost::move(x)); return iterator(this->icont().insert(p.get(), *tmp)); } diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 9e28002..8e7aa20 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2004-2015. 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) // @@ -684,7 +684,10 @@ class slist //! //! Complexity: Constant. reference front() - { return *this->begin(); } + { + BOOST_ASSERT(!this->empty()); + return *this->begin(); + } //! Requires: !empty() //! @@ -695,7 +698,10 @@ class slist //! //! Complexity: Constant. const_reference front() const - { return *this->begin(); } + { + BOOST_ASSERT(!this->empty()); + return *this->begin(); + } ////////////////////////////////////////////// // @@ -897,7 +903,10 @@ class slist //! //! Complexity: Amortized constant time. void pop_front() - { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } + { + BOOST_ASSERT(!this->empty()); + this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); + } //! Effects: Erases the element after the element pointed by prev_p //! of the list. @@ -939,7 +948,12 @@ class slist void swap(slist& x) BOOST_NOEXCEPT_IF( allocator_traits_type::propagate_on_container_swap::value || allocator_traits_type::is_always_equal::value) - { AllocHolder::swap(x); } + { + BOOST_ASSERT(allocator_traits_type::propagate_on_container_swap::value || + allocator_traits_type::is_always_equal::value || + this->get_stored_allocator() == x.get_stored_allocator()); + AllocHolder::swap(x); + } //! Effects: Erases all the elements of the list. //! diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 22c5453..4a4a47b 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2015. 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) // @@ -1196,7 +1196,10 @@ class stable_vector //! //! Complexity: Constant. reference front() BOOST_NOEXCEPT_OR_NOTHROW - { return static_cast(*this->index.front()).value; } + { + BOOST_ASSERT(!this->empty()); + return static_cast(*this->index.front()).value; + } //! Requires: !empty() //! @@ -1207,7 +1210,10 @@ class stable_vector //! //! Complexity: Constant. const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW - { return static_cast(*this->index.front()).value; } + { + BOOST_ASSERT(!this->empty()); + return static_cast(*this->index.front()).value; + } //! Requires: !empty() //! @@ -1218,7 +1224,10 @@ class stable_vector //! //! Complexity: Constant. reference back() BOOST_NOEXCEPT_OR_NOTHROW - { return static_cast(*this->index[this->size()-1u]).value; } + { + BOOST_ASSERT(!this->empty()); + return static_cast(*this->index[this->size()-1u]).value; + } //! Requires: !empty() //! @@ -1229,7 +1238,10 @@ class stable_vector //! //! Complexity: Constant. const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW - { return static_cast(*this->index[this->size()-1u]).value; } + { + BOOST_ASSERT(!this->empty()); + return static_cast(*this->index[this->size()-1u]).value; + } //! Requires: size() > n. //! @@ -1241,7 +1253,7 @@ class stable_vector //! Complexity: Constant. reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_ASSERT(n < this->size()); + BOOST_ASSERT(this->size() > n); return static_cast(*this->index[n]).value; } @@ -1255,7 +1267,7 @@ class stable_vector //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_ASSERT(n < this->size()); + BOOST_ASSERT(this->size() > n); return static_cast(*this->index[n]).value; } @@ -1386,6 +1398,7 @@ class stable_vector template iterator emplace(const_iterator p, Args && ...args) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); size_type pos_n = p - cbegin(); typedef emplace_functor EmplaceFunctor; typedef emplace_iterator EmplaceIterator; @@ -1410,6 +1423,7 @@ class stable_vector BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ + BOOST_ASSERT(this->priv_in_range_or_end(p));\ typedef emplace_functor##N\ BOOST_MOVE_LT##N BOOST_MOVE_TARG##N BOOST_MOVE_GT##N EmplaceFunctor;\ typedef emplace_iterator EmplaceIterator;\ @@ -1483,6 +1497,7 @@ class stable_vector //! Complexity: Linear to n. iterator insert(const_iterator p, size_type n, const T& t) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); STABLE_VECTOR_CHECK_INVARIANT; typedef constant_iterator cvalue_iterator; return this->insert(p, cvalue_iterator(t, n), cvalue_iterator()); @@ -1499,6 +1514,7 @@ class stable_vector //! Complexity: Linear to distance [il.begin(), il.end()). iterator insert(const_iterator p, std::initializer_list il) { + //Position checks done by insert() STABLE_VECTOR_CHECK_INVARIANT; return insert(p, il.begin(), il.end()); } @@ -1526,6 +1542,7 @@ class stable_vector #endif insert(const_iterator p, InputIterator first, InputIterator last) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); STABLE_VECTOR_CHECK_INVARIANT; const size_type pos_n = p - this->cbegin(); for(; first != last; ++first){ @@ -1543,6 +1560,7 @@ class stable_vector >::type insert(const_iterator p, FwdIt first, FwdIt last) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); const size_type num_new = static_cast(boost::container::iterator_distance(first, last)); const size_type idx = static_cast(p - this->cbegin()); if(num_new){ @@ -1581,7 +1599,10 @@ class stable_vector //! //! Complexity: Constant time. void pop_back() BOOST_NOEXCEPT_OR_NOTHROW - { this->erase(--this->cend()); } + { + BOOST_ASSERT(!this->empty()); + this->erase(--this->cend()); + } //! Effects: Erases the element at p. //! @@ -1591,6 +1612,7 @@ class stable_vector //! last element. Constant if p is the last element. iterator erase(const_iterator p) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(this->priv_in_range(p)); STABLE_VECTOR_CHECK_INVARIANT; const size_type d = p - this->cbegin(); index_iterator it = this->index.begin() + d; @@ -1608,6 +1630,9 @@ class stable_vector //! plus linear to the elements between p and the last element. iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(first <= last); + BOOST_ASSERT(first == last || this->priv_in_range(first)); + BOOST_ASSERT(first == last || this->priv_in_range_or_end(last)); STABLE_VECTOR_CHECK_INVARIANT; const const_iterator cbeg(this->cbegin()); const size_type d1 = static_cast(first - cbeg), @@ -1641,6 +1666,9 @@ class stable_vector BOOST_NOEXCEPT_IF( allocator_traits_type::propagate_on_container_swap::value || allocator_traits_type::is_always_equal::value) { + BOOST_ASSERT(allocator_traits_type::propagate_on_container_swap::value || + allocator_traits_type::is_always_equal::value || + this->get_stored_allocator() == x.get_stored_allocator()); STABLE_VECTOR_CHECK_INVARIANT; container_detail::bool_ flag; container_detail::swap_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); @@ -1702,6 +1730,16 @@ class stable_vector #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + bool priv_in_range(const_iterator pos) const + { + return (this->begin() <= pos) && (pos < this->end()); + } + + bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } + size_type priv_index_of(node_ptr p) const { //Check range @@ -1807,12 +1845,14 @@ class stable_vector iterator priv_insert(const_iterator p, const value_type &t) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); typedef constant_iterator cvalue_iterator; return this->insert(p, cvalue_iterator(t, 1), cvalue_iterator()); } iterator priv_insert(const_iterator p, BOOST_RV_REF(T) x) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); typedef repeat_iterator repeat_it; typedef boost::move_iterator repeat_move_it; //Just call more general insert(p, size, value) and return iterator diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index e27419c..40dec81 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2014. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2015. 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) // @@ -1097,6 +1097,7 @@ class vector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { + BOOST_ASSERT(&x != this); this->priv_move_assign(boost::move(x)); return *this; } @@ -1512,7 +1513,10 @@ class vector //! //! Complexity: Constant. reference front() BOOST_NOEXCEPT_OR_NOTHROW - { return *this->m_holder.start(); } + { + BOOST_ASSERT(!this->empty()); + return *this->m_holder.start(); + } //! Requires: !empty() //! @@ -1523,7 +1527,10 @@ class vector //! //! Complexity: Constant. const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->m_holder.start(); } + { + BOOST_ASSERT(!this->empty()); + return *this->m_holder.start(); + } //! Requires: !empty() //! @@ -1535,7 +1542,7 @@ class vector //! Complexity: Constant. reference back() BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_ASSERT(this->m_holder.m_size > 0); + BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; } @@ -1549,7 +1556,7 @@ class vector //! Complexity: Constant. const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_ASSERT(this->m_holder.m_size > 0); + BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; } @@ -1577,7 +1584,8 @@ class vector //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { - return this->m_holder.start()[n]; + BOOST_ASSERT(this->m_holder.m_size > n); + return this->m_holder.start()[n]; } //! Requires: size() >= n. @@ -1626,7 +1634,10 @@ class vector //! //! Note: Non-standard extension size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_index_of(vector_iterator_get_ptr(p)); } + { + //Range check assert done in priv_index_of + return this->priv_index_of(vector_iterator_get_ptr(p)); + } //! Requires: begin() <= p <= end(). //! @@ -1639,7 +1650,10 @@ class vector //! //! Note: Non-standard extension size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_index_of(vector_iterator_get_ptr(p)); } + { + //Range check assert done in priv_index_of + return this->priv_index_of(vector_iterator_get_ptr(p)); + } //! Requires: size() > n. //! @@ -1650,7 +1664,10 @@ class vector //! //! Complexity: Constant. reference at(size_type n) - { this->priv_check_range(n); return this->m_holder.start()[n]; } + { + this->priv_throw_if_out_of_range(n); + return this->m_holder.start()[n]; + } //! Requires: size() > n. //! @@ -1661,7 +1678,10 @@ class vector //! //! Complexity: Constant. const_reference at(size_type n) const - { this->priv_check_range(n); return this->m_holder.start()[n]; } + { + this->priv_throw_if_out_of_range(n); + return this->m_holder.start()[n]; + } ////////////////////////////////////////////// // @@ -1749,6 +1769,7 @@ class vector template iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) { + BOOST_ASSERT(this->priv_in_range_or_end(position)); //Just call more general insert(pos, size, value) and return iterator typedef container_detail::insert_emplace_proxy type; return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1 @@ -1788,6 +1809,7 @@ class vector BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ + BOOST_ASSERT(this->priv_in_range_or_end(pos));\ typedef container_detail::insert_emplace_proxy_arg##N type;\ return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), 1, type(BOOST_MOVE_FWD##N));\ }\ @@ -1853,6 +1875,7 @@ class vector //! Complexity: Linear to n. iterator insert(const_iterator p, size_type n, const T& x) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); container_detail::insert_n_copies_proxy proxy(x); return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy); } @@ -1878,6 +1901,7 @@ class vector #endif ) { + BOOST_ASSERT(this->priv_in_range_or_end(pos)); const size_type n_pos = pos - this->cbegin(); iterator it(vector_iterator_get_ptr(pos)); for(;first != last; ++first){ @@ -1897,6 +1921,7 @@ class vector >::type * = 0 ) { + BOOST_ASSERT(this->priv_in_range_or_end(pos)); container_detail::insert_range_proxy proxy(first); return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy); } @@ -1921,6 +1946,7 @@ class vector template iterator insert(const_iterator pos, size_type num, InIt first, InIt last) { + BOOST_ASSERT(this->priv_in_range_or_end(pos)); BOOST_ASSERT(container_detail::is_input_iterator::value || num == static_cast(boost::container::iterator_distance(first, last))); (void)last; @@ -1939,17 +1965,19 @@ class vector //! Complexity: Linear to the range [il.begin(), il.end()). iterator insert(const_iterator position, std::initializer_list il) { + //Assertion done in insert() return this->insert(position, il.begin(), il.end()); } #endif - //! Effects: Removes the last element from the vector. + //! Effects: Removes the last element from the container. //! //! Throws: Nothing. //! //! Complexity: Constant time. void pop_back() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT(!this->empty()); //Destroy last element this->priv_destroy_last(); } @@ -1962,6 +1990,7 @@ class vector //! last element. Constant if pos is the last element. iterator erase(const_iterator position) { + BOOST_ASSERT(this->priv_in_range(position)); const pointer p = vector_iterator_get_ptr(position); T *const pos_ptr = container_detail::to_raw_pointer(p); T *const beg_ptr = container_detail::to_raw_pointer(this->m_holder.start()); @@ -1979,6 +2008,9 @@ class vector //! plus linear to the elements between pos and the last element. iterator erase(const_iterator first, const_iterator last) { + BOOST_ASSERT(first <= last); + BOOST_ASSERT(first == last || this->priv_in_range(first)); + BOOST_ASSERT(first == last || this->priv_in_range_or_end(last)); if (first != last){ T* const old_end_ptr = this->back_raw(); T* const first_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(first)); @@ -2571,6 +2603,7 @@ class vector template iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) { + BOOST_ASSERT(this->priv_in_range_or_end(p)); return this->priv_forward_range_insert ( vector_iterator_get_ptr(p), 1, container_detail::get_insert_value_proxy(::boost::forward(x))); } @@ -3292,7 +3325,7 @@ class vector } } - void priv_check_range(size_type n) const + void priv_throw_if_out_of_range(size_type n) const { //If n is out of range, throw an out_of_range exception if (n >= this->size()){ @@ -3300,6 +3333,16 @@ class vector } } + bool priv_in_range(const_iterator pos) const + { + return (this->begin() <= pos) && (pos < this->end()); + } + + bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS public: unsigned int num_expand_fwd;