diff --git a/include/boost/archive/iterators/remove_whitespace.hpp b/include/boost/archive/iterators/remove_whitespace.hpp index a89c33314..ab6586fe9 100644 --- a/include/boost/archive/iterators/remove_whitespace.hpp +++ b/include/boost/archive/iterators/remove_whitespace.hpp @@ -100,6 +100,13 @@ class filter_iterator typedef filter_iterator this_t; typedef typename super_t::reference reference_type; + void satisfy_predicate(){ + while(this->base_reference() != m_end + && ! m_predicate(* this->base_reference())){ + ++(this->base_reference()); + } + } + reference_type dereference_impl(){ if(! m_full){ while(! m_predicate(* this->base_reference())) @@ -110,23 +117,47 @@ class filter_iterator } reference_type dereference() const { + if(m_bounded){ + return * this->base_reference(); + } return const_cast(this)->dereference_impl(); } Predicate m_predicate; bool m_full; + Base m_end; + bool m_bounded; public: // note: this function is public only because comeau compiler complained // I don't know if this is because the compiler is wrong or what void increment(){ - m_full = false; ++(this->base_reference()); + if(m_bounded){ + satisfy_predicate(); + } + else{ + m_full = false; + } } filter_iterator(Base start) : super_t(start), - m_full(false) + m_full(false), + m_end(), + m_bounded(false) + {} + filter_iterator(Base start, Base end) : + super_t(start), + m_full(false), + m_end(end), + m_bounded(true) + { + satisfy_predicate(); + } + filter_iterator() : + m_full(false), + m_end(), + m_bounded(false) {} - filter_iterator(){} }; template @@ -154,6 +185,10 @@ class remove_whitespace : remove_whitespace(T start) : super_t(Base(static_cast< T >(start))) {} + template + remove_whitespace(T start, T end) : + super_t(Base(static_cast< T >(start)), Base(static_cast< T >(end))) + {} }; } // namespace iterators diff --git a/test/test_iterators.cpp b/test/test_iterators.cpp index 36e8d22d0..22a04b4fe 100644 --- a/test/test_iterators.cpp +++ b/test/test_iterators.cpp @@ -10,6 +10,7 @@ #include // for rand #include #include // used to test stream iterators +#include #include #include // begin #include // setlocale @@ -32,6 +33,7 @@ namespace std{ #endif #include #include +#include #include #include #include @@ -195,6 +197,23 @@ void test_stream_iterators( BOOST_CHECK(std::equal(test_data, test_data + size,isi)); } +// Regression test for issue #254: the bounded (two-argument) filter form +// must handle a range that ends in a non-matching element without running +// past the end. +void test_remove_whitespace(){ + typedef boost::archive::iterators::remove_whitespace translator; + + const char with_ws[] = " a b\tc \n"; // leading, embedded and trailing ws + const char * b = with_ws; + const char * e = with_ws + sizeof(with_ws) / sizeof(char) - 1; + BOOST_CHECK(std::string(translator(b, e), translator(e, e)) == "abc"); + + const char all_ws[] = " "; // filters to empty, must not overrun + const char * wb = all_ws; + const char * we = all_ws + sizeof(all_ws) / sizeof(char) - 1; + BOOST_CHECK(std::string(translator(wb, we), translator(we, we)).empty()); +} + int test_main(int /* argc */, char* /* argv */ [] ) { @@ -253,5 +272,7 @@ test_main(int /* argc */, char* /* argv */ [] ) test_transform_width<6, 8>(7); test_transform_width<6, 8>(8); + test_remove_whitespace(); + return EXIT_SUCCESS; }