added the boost::range::separated function for range output streaming.

This commit is contained in:
Neil Groves
2014-03-09 21:09:00 +00:00
parent 70256bd8b0
commit a6bd3e6e44
5 changed files with 254 additions and 0 deletions

View File

@ -63,6 +63,8 @@
[def __counting_range__ [link range.reference.ranges.counting_range `counting_range`]] [def __counting_range__ [link range.reference.ranges.counting_range `counting_range`]]
[def __irange__ [link range.reference.ranges.irange `irange`]] [def __irange__ [link range.reference.ranges.irange `irange`]]
[def __istream_range__ [link range.reference.ranges.istream_range `istream_range`]] [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 __join__ [link range.reference.utilities.join `join`]]
[def __range_adaptors__ [link range.reference.adaptors Range adaptors]] [def __range_adaptors__ [link range.reference.adaptors Range adaptors]]

View File

@ -10,6 +10,7 @@ Having an abstraction that encapsulates a pair of iterators is very useful. The
* Class `iterator_range` * Class `iterator_range`
* Class `sub_range` * Class `sub_range`
* Function `combine` * Function `combine`
* Function `separated`
* Function `join` * 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. 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)` 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<typename Iterator, typename Separator>
class output_stream_writer
{
// ... unspecified
};
template<typename Char, typename Traits>
std::basic_ostream<Char,Traits>& operator<<(
std::basic_ostream<Char,Traits>& out,
const output_stream_writer<Iterator, Separator>& writer);
template<typename Range, typename Separator>
boost::range::output_stream_writer<
typename boost::range_iterator<const Range>::type,
Separator
> separated(const Range& rng, Separator separator);
``
[h4 Example]
``
#include <boost/range/separated.hpp>
#include <iostream>
#include <vector>
int main(int, const char*[])
{
std::vector<int> 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]
[endsect] [endsect]

View File

@ -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 <boost/config.hpp>
#include <boost/range/concepts.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <ostream>
namespace boost
{
namespace range_detail
{
template<typename Iter, typename Separator>
class output_stream_writer
{
public:
output_stream_writer(Iter first, Iter last, Separator separator)
: m_first(first)
, m_last(last)
, m_separator(separator)
{
}
template<typename OStream>
void write(OStream& out) const
{
write_impl(out, m_first, m_last, m_separator);
}
private:
template<typename OStream>
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<typename Char, typename Traits, typename Iter, typename Separator>
std::basic_ostream<Char, Traits>&
operator<<(
std::basic_ostream<Char, Traits>& out,
const output_stream_writer<Iter, Separator>& writer)
{
writer.write(out);
return out;
}
} // namespace range_detail
namespace range
{
template<typename Range, typename Separator>
inline range_detail::output_stream_writer<
typename range_iterator<const Range>::type,
Separator
>
separated(const Range& rng, Separator separator)
{
BOOST_RANGE_CONCEPT_ASSERT((SinglePassRangeConcept<const Range>));
return range_detail::output_stream_writer<
typename range_iterator<const Range>::type,
Separator
>(boost::begin(rng), boost::end(rng), separator);
}
} // namespace range
} // namespace boost
#endif // include guard

View File

@ -179,6 +179,7 @@ test-suite range :
[ range-test reverse_iterator ] [ range-test reverse_iterator ]
[ range-test reverse_result_iterator ] [ range-test reverse_result_iterator ]
[ range-test reversible_range ] [ range-test reversible_range ]
[ range-test separated ]
[ range-test size_type ] [ range-test size_type ]
[ range-test std_container ] [ range-test std_container ]
[ range-test string ] [ range-test string ]

107
test/separated.cpp Normal file
View File

@ -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 <boost/range/separated.hpp>
#include <boost/cstdint.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
namespace boost_range_test
{
namespace
{
void test_separated1()
{
std::vector<boost::int32_t> 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<boost::int32_t> v;
v.push_back(3);
std::ostringstream out;
out << '{' << boost::range::separated(v, ',') << '}';
BOOST_CHECK_EQUAL(out.str(), "{3}");
}
void test_separated3()
{
std::vector<boost::int32_t> v;
std::ostringstream out;
out << '{' << boost::range::separated(v, ',') << '}';
BOOST_CHECK_EQUAL(out.str(), "{}");
}
void test_separated4()
{
std::vector<boost::int32_t> 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<typename Char, typename Traits>
inline std::basic_ostream<Char,Traits>&
operator<<(std::basic_ostream<Char,Traits>& out, udt_separator)
{
return out << "[sep]";
}
void test_separated5()
{
std::vector<boost::int32_t> 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;
}