From f1de74a6aca6c282b18537a204be4c77c3a52b2f Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 9 Mar 2014 17:59:35 +0000 Subject: [PATCH 1/4] ticket 9438 for qualifying calls to ignore_unused_variable_warning --- include/boost/range/concepts.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/range/concepts.hpp b/include/boost/range/concepts.hpp index 467858b..d957c1b 100644 --- a/include/boost/range/concepts.hpp +++ b/include/boost/range/concepts.hpp @@ -285,8 +285,8 @@ namespace boost { iterator i1 = boost::begin(*m_range); iterator i2 = boost::end(*m_range); - ignore_unused_variable_warning(i1); - ignore_unused_variable_warning(i2); + boost::ignore_unused_variable_warning(i1); + boost::ignore_unused_variable_warning(i2); const_constraints(*m_range); } @@ -297,8 +297,8 @@ namespace boost { const_iterator ci1 = boost::begin(const_range); const_iterator ci2 = boost::end(const_range); - ignore_unused_variable_warning(ci1); - ignore_unused_variable_warning(ci2); + boost::ignore_unused_variable_warning(ci1); + boost::ignore_unused_variable_warning(ci2); } // Rationale: From 70256bd8b04036eb9c5db12bc603f84fa8a35541 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 9 Mar 2014 19:27:28 +0000 Subject: [PATCH 2/4] ticket 4572 - make_iterator_range_n --- doc/reference/utilities.qbk | 6 +++++ include/boost/range/iterator_range_core.hpp | 7 ++++++ test/iterator_range.cpp | 26 ++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/doc/reference/utilities.qbk b/doc/reference/utilities.qbk index b39904f..2a18f35 100644 --- a/doc/reference/utilities.qbk +++ b/doc/reference/utilities.qbk @@ -132,6 +132,12 @@ namespace boost make_iterator_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End ); + // Make an iterator_range [first, boost::next(first, n) ) + template< class ForwardTraversalIterator, class Integer > + iterator_range< ForwardTraversalIterator > + make_iterator_range_n( ForwardTraversalIterator first, Integer n ); + + template< class ForwardRange > iterator_range< typename range_iterator::type > make_iterator_range( ForwardRange& r ); diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index ba842ab..e6c77f5 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -651,6 +651,13 @@ public: return iterator_range( Begin, End ); } + template + inline iterator_range + make_iterator_range_n(IteratorT first, IntegerT n) + { + return iterator_range(first, boost::next(first, n)); + } + #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING template< typename Range > diff --git a/test/iterator_range.cpp b/test/iterator_range.cpp index c914f43..688116d 100644 --- a/test/iterator_range.cpp +++ b/test/iterator_range.cpp @@ -213,7 +213,30 @@ namespace iterator_range_test_detail BOOST_CHECK_EQUAL_COLLECTIONS( rng.begin(), rng.end(), source, source + 6 ); } - + + void check_make_iterator_range_n() + { + std::vector input; + for (uint32_t i = 0; i < 10u; ++i) + input.push_back(i); + + boost::iterator_range::iterator> rng = + boost::make_iterator_range_n(boost::begin(input), 8u); + + BOOST_CHECK(rng.begin() == input.begin()); + BOOST_CHECK(rng.end() == input.begin() + 8); + BOOST_CHECK_EQUAL(rng.size(), 8u); + + const std::vector& cinput = input; + + boost::iterator_range::const_iterator> crng = + boost::make_iterator_range_n(boost::begin(cinput), 8u); + + BOOST_CHECK(crng.begin() == cinput.begin()); + BOOST_CHECK(crng.end() == cinput.begin() + 8); + BOOST_CHECK_EQUAL(crng.size(), 8u); + } + } // namespace iterator_range_test_detail template @@ -234,6 +257,7 @@ boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) test->add(BOOST_TEST_CASE(&check_iterator_range_operator)); test->add(BOOST_TEST_CASE(&check_iterator_range_operator)); test->add(BOOST_TEST_CASE(&check_iterator_range_operator)); + test->add(BOOST_TEST_CASE(&iterator_range_test_detail::check_make_iterator_range_n)); return test; } From a6bd3e6e447f4e2a15c6801958ca1f518917facb Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 9 Mar 2014 21:09:00 +0000 Subject: [PATCH 3/4] added the boost::range::separated function for range output streaming. --- doc/boost_range.qbk | 2 + doc/reference/utilities.qbk | 50 ++++++++++++++ include/boost/range/separated.hpp | 94 ++++++++++++++++++++++++++ test/Jamfile.v2 | 1 + test/separated.cpp | 107 ++++++++++++++++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 include/boost/range/separated.hpp create mode 100644 test/separated.cpp diff --git a/doc/boost_range.qbk b/doc/boost_range.qbk index 126ec62..406d1a8 100644 --- a/doc/boost_range.qbk +++ b/doc/boost_range.qbk @@ -63,6 +63,8 @@ [def __counting_range__ [link range.reference.ranges.counting_range `counting_range`]] [def __irange__ [link range.reference.ranges.irange `irange`]] [def __istream_range__ [link range.reference.ranges.istream_range `istream_range`]] +[def __combine__ [link range.reference.utilities.combine `combine`]] +[def __separated__ [link range.reference.utilities.separated `separated`]] [def __join__ [link range.reference.utilities.join `join`]] [def __range_adaptors__ [link range.reference.adaptors Range adaptors]] diff --git a/doc/reference/utilities.qbk b/doc/reference/utilities.qbk index 2a18f35..a86a3f4 100644 --- a/doc/reference/utilities.qbk +++ b/doc/reference/utilities.qbk @@ -10,6 +10,7 @@ Having an abstraction that encapsulates a pair of iterators is very useful. The * Class `iterator_range` * Class `sub_range` * Function `combine` +* Function `separated` * Function `join` The `iterator_range` class is templated on an __forward_traversal_iterator__ and should be used whenever fairly general code is needed. The `sub_range` class is templated on an __forward_range__ and it is less general, but a bit easier to use since its template argument is easier to specify. The biggest difference is, however, that a `sub_range` can propagate constness because it knows what a corresponding `const_iterator` is. @@ -404,6 +405,55 @@ For the mutable version: The expression `join(irange(0,5), irange(5,10))` would evaluate to a range representing an integer range `[0,10)` +[endsect] + +[section:separated Function separated] + +The separated function allows output streaming a range while writing a separator +between each element. + +[h4 Synopsis] + +`` +template +class output_stream_writer +{ + // ... unspecified +}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& out, + const output_stream_writer& writer); + +template +boost::range::output_stream_writer< + typename boost::range_iterator::type, + Separator +> separated(const Range& rng, Separator separator); +`` + +[h4 Example] + +`` +#include +#include +#include + +int main(int, const char*[]) +{ + std::vector v; + for (int i = 0; i < 5; ++i) + v.push_back(v); + + std::cout << '{' << boost::range::separated(v, ',') << '}' << std::endl; + + return 0; +} +`` + +Produces the output: `{0,1,2,3,4}` + [endsect] [endsect] diff --git a/include/boost/range/separated.hpp b/include/boost/range/separated.hpp new file mode 100644 index 0000000..556441e --- /dev/null +++ b/include/boost/range/separated.hpp @@ -0,0 +1,94 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. +// Use, modification and distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_SEPARATED_HPP_INCLUDED +#define BOOST_RANGE_SEPARATED_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace range_detail + { + +template +class output_stream_writer +{ +public: + output_stream_writer(Iter first, Iter last, Separator separator) + : m_first(first) + , m_last(last) + , m_separator(separator) + { + } + + template + void write(OStream& out) const + { + write_impl(out, m_first, m_last, m_separator); + } + +private: + template + static void write_impl( + OStream& out, Iter first, Iter last, Separator separator) + { + if (first != last) + { + out << *first; + for (++first; first != last; ++first) + { + out << separator << *first; + } + } + } + + Iter m_first; + Iter m_last; + Separator m_separator; +}; + +template +std::basic_ostream& +operator<<( + std::basic_ostream& out, + const output_stream_writer& writer) +{ + writer.write(out); + return out; +} + + } // namespace range_detail + + namespace range + { + +template +inline range_detail::output_stream_writer< + typename range_iterator::type, + Separator +> +separated(const Range& rng, Separator separator) +{ + BOOST_RANGE_CONCEPT_ASSERT((SinglePassRangeConcept)); + return range_detail::output_stream_writer< + typename range_iterator::type, + Separator + >(boost::begin(rng), boost::end(rng), separator); +} + + } // namespace range +} // namespace boost + +#endif // include guard diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 59251f1..4354c3f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -179,6 +179,7 @@ test-suite range : [ range-test reverse_iterator ] [ range-test reverse_result_iterator ] [ range-test reversible_range ] + [ range-test separated ] [ range-test size_type ] [ range-test std_container ] [ range-test string ] diff --git a/test/separated.cpp b/test/separated.cpp new file mode 100644 index 0000000..680558d --- /dev/null +++ b/test/separated.cpp @@ -0,0 +1,107 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. Use, modification and +// distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost_range_test +{ + namespace + { + +void test_separated1() +{ + std::vector v; + for (boost::int32_t i = 0; i < 10; ++i) + v.push_back(i); + + std::ostringstream out; + out << '{' << boost::range::separated(v, ',') << '}'; + + BOOST_CHECK_EQUAL(out.str(), "{0,1,2,3,4,5,6,7,8,9}"); +} + +void test_separated2() +{ + std::vector v; + v.push_back(3); + + std::ostringstream out; + out << '{' << boost::range::separated(v, ',') << '}'; + + BOOST_CHECK_EQUAL(out.str(), "{3}"); +} + +void test_separated3() +{ + std::vector v; + + std::ostringstream out; + out << '{' << boost::range::separated(v, ',') << '}'; + + BOOST_CHECK_EQUAL(out.str(), "{}"); +} + +void test_separated4() +{ + std::vector v; + for (boost::int32_t i = 0; i < 5; ++i) + v.push_back(i); + + std::ostringstream out; + out << '{' << boost::range::separated(v, "::") << '}'; + + BOOST_CHECK_EQUAL(out.str(), "{0::1::2::3::4}"); +} + +struct udt_separator +{ +}; + +template +inline std::basic_ostream& +operator<<(std::basic_ostream& out, udt_separator) +{ + return out << "[sep]"; +} + +void test_separated5() +{ + std::vector v; + for (boost::int32_t i = 0; i < 5; ++i) + v.push_back(i); + + std::ostringstream out; + out << '{' << boost::range::separated(v, udt_separator()) << '}'; + + BOOST_CHECK_EQUAL(out.str(), "{0[sep]1[sep]2[sep]3[sep]4}"); +} + + } // anonymous namespace +} // namespace boost_range_test + +boost::unit_test::test_suite* init_unit_test_suite(int, char*[] ) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE( "Boost.Range separated test suite" ); + + test->add(BOOST_TEST_CASE(&boost_range_test::test_separated1)); + test->add(BOOST_TEST_CASE(&boost_range_test::test_separated2)); + test->add(BOOST_TEST_CASE(&boost_range_test::test_separated3)); + test->add(BOOST_TEST_CASE(&boost_range_test::test_separated4)); + test->add(BOOST_TEST_CASE(&boost_range_test::test_separated5)); + + return test; +} From ed0febc90211f4302b724f38419928481d9b168c Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 9 Mar 2014 21:51:07 +0000 Subject: [PATCH 4/4] ticket 6172 - added unit test to ensure transformed works with bind. --- include/boost/range/adaptor/transformed.hpp | 37 +++++++++++++++++++-- test/adaptor_test/transformed.cpp | 27 ++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/include/boost/range/adaptor/transformed.hpp b/include/boost/range/adaptor/transformed.hpp index 96d2dab..98c655e 100755 --- a/include/boost/range/adaptor/transformed.hpp +++ b/include/boost/range/adaptor/transformed.hpp @@ -41,20 +41,32 @@ namespace boost typedef F transform_fn_type; typedef R source_range_type; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES transformed_range( F f, R& r ) : base( boost::make_transform_iterator( boost::begin(r), f ), boost::make_transform_iterator( boost::end(r), f ) ) - { } + { + } +#else + transformed_range(F&& f, R&& r) + : base(typename base::iterator(boost::begin(r), std::forward(f), + typename base::iterator(boost::end(r), std::forward(f)))) + { + } + +#endif }; template< class T > struct transform_holder : holder { transform_holder( T r ) : holder(r) - { } + { + } }; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES template< class InputRng, class UnaryFunction > inline transformed_range operator|( InputRng& r, @@ -70,6 +82,16 @@ namespace boost { return transformed_range( f.val, r ); } +#else + template + inline transformed_range + operator|(InputRng&& r, + transform_holder&& f) + { + return transformed_range( + f.val, std::forward(r)); + } +#endif } // 'range_detail' @@ -84,6 +106,7 @@ namespace boost range_detail::forwarder(); } +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES template inline transformed_range transform(InputRange& rng, UnaryFunction fn) @@ -97,6 +120,16 @@ namespace boost { return transformed_range(fn, rng); } +#else + template + inline transformed_range + transform(InputRange&& rng, UnaryFunction&& fn) + { + return transformed_range( + std::forward(fn), std::forward(rng)); + } + +#endif } // 'adaptors' } diff --git a/test/adaptor_test/transformed.cpp b/test/adaptor_test/transformed.cpp index 6b6121e..adadafc 100644 --- a/test/adaptor_test/transformed.cpp +++ b/test/adaptor_test/transformed.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -92,6 +93,29 @@ namespace boost transformed_test_impl< std::set< int > >(); transformed_test_impl< std::multiset< int > >(); } + + struct foo_bind + { + int foo() const { return 7; } + }; + + void transformed_bind() + { + using namespace boost::adaptors; + + std::vector input(5); + std::vector output; + boost::range::push_back( + output, + input | transformed(boost::bind(&foo_bind::foo, _1))); + + BOOST_CHECK_EQUAL(output.size(), input.size()); + + std::vector reference_output(5, 7); + BOOST_CHECK_EQUAL_COLLECTIONS( + output.begin(), output.end(), + reference_output.begin(), reference_output.end()); + } } } @@ -101,7 +125,8 @@ init_unit_test_suite(int argc, char* argv[]) boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.transformed" ); - test->add( BOOST_TEST_CASE( &boost::transformed_test ) ); + test->add(BOOST_TEST_CASE(&boost::transformed_test)); + test->add(BOOST_TEST_CASE(&boost::transformed_bind)); return test; }