mirror of
https://github.com/boostorg/io.git
synced 2025-07-29 11:57:14 +02:00
Implement ostream_joiner
This commit is contained in:
5
doc/io-docinfo-footer.html
Normal file
5
doc/io-docinfo-footer.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<style>
|
||||||
|
.specification {
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
@ -7,7 +7,8 @@ Distributed under the Boost Software License, Version 1.0.
|
|||||||
////
|
////
|
||||||
|
|
||||||
# Boost.IO
|
# Boost.IO
|
||||||
Daryle Walker, Beman Dawes
|
Daryle Walker, Beman Dawes, Glen Joseph Fernandes <glenjofe@gmail.com>
|
||||||
|
:docinfo: private-footer
|
||||||
:idprefix:
|
:idprefix:
|
||||||
:source-language: cpp
|
:source-language: cpp
|
||||||
:toc: left
|
:toc: left
|
||||||
@ -19,6 +20,7 @@ library.
|
|||||||
:leveloffset: +1
|
:leveloffset: +1
|
||||||
|
|
||||||
include::ios_state.adoc[]
|
include::ios_state.adoc[]
|
||||||
|
include::ostream_joiner.adoc[]
|
||||||
|
|
||||||
:leveloffset: -1
|
:leveloffset: -1
|
||||||
|
|
||||||
|
143
doc/ostream_joiner.adoc
Normal file
143
doc/ostream_joiner.adoc
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
////
|
||||||
|
Copyright 2019 Glen Joseph Fernandes
|
||||||
|
(glenjofe@gmail.com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
////
|
||||||
|
|
||||||
|
# ostream_joiner, <boost/io/ostream_joiner.hpp>
|
||||||
|
:toc:
|
||||||
|
:toc-title:
|
||||||
|
:idprefix:
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
The header `<boost/io/ostream_joiner.hpp>` provides the class template
|
||||||
|
`boost::io::ostream_joiner` which is an output iterator that writes objects to
|
||||||
|
a `std::basic_ostream` separated by a delimiter. It is an implementation of
|
||||||
|
the Library Fundamentals TS `std::ostream_joiner` which supports {cpp}03 and
|
||||||
|
higher.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The following program writes the contents of a vector to standard output, with
|
||||||
|
each element separated by a comma.
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <boost/io/ostream_joiner.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::vector<int> v;
|
||||||
|
v.push_back(2);
|
||||||
|
v.push_back(4);
|
||||||
|
v.push_back(6);
|
||||||
|
v.push_back(8);
|
||||||
|
std::copy(v.begin(), v.end(), boost::make_ostream_joiner(std::cout, ','));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
### Header Synopsis
|
||||||
|
|
||||||
|
```
|
||||||
|
namespace boost {
|
||||||
|
namespace io {
|
||||||
|
|
||||||
|
template<class Delim, class Char = char,
|
||||||
|
class Traits = std::char_traits<Char> >
|
||||||
|
class ostream_joiner {
|
||||||
|
public:
|
||||||
|
typedef Char char_type;
|
||||||
|
typedef Traits traits_type;
|
||||||
|
typedef std::basic_ostream<Char, Traits> ostream_type;
|
||||||
|
typedef std::output_iterator_tag iterator_category;
|
||||||
|
typedef void value_type;
|
||||||
|
typedef void difference_type;
|
||||||
|
typedef void pointer;
|
||||||
|
typedef void reference;
|
||||||
|
|
||||||
|
ostream_joiner(ostream_type& output, const Delim& delim);
|
||||||
|
ostream_joiner(ostream_type& output, Delim&& delim);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
ostream_joiner& operator=(const T& value);
|
||||||
|
|
||||||
|
ostream_joiner& operator*() noexcept;
|
||||||
|
ostream_joiner& operator++() noexcept;
|
||||||
|
ostream_joiner& operator++(int) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Char, class Traits, class Delim>
|
||||||
|
ostream_joiner<std::decay_t<Delim>, Char, Traits>
|
||||||
|
make_ostream_joiner(std::basic_ostream<Char, Traits>& output, Delim&& delim);
|
||||||
|
|
||||||
|
} // io
|
||||||
|
} // boost
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructors
|
||||||
|
|
||||||
|
```
|
||||||
|
ostream_joiner(ostream_type& output, const Delim& delim);
|
||||||
|
```
|
||||||
|
|
||||||
|
[.specification]
|
||||||
|
EFfects:: Initializes the stored reference to the stream with
|
||||||
|
`std::addressof(output)` and the stored delimiter with `delim`.
|
||||||
|
|
||||||
|
```
|
||||||
|
ostream_joiner(ostream_type& output, Delim&& delim);
|
||||||
|
```
|
||||||
|
|
||||||
|
[.specification]
|
||||||
|
EFfects:: Initializes the stored reference to the stream with
|
||||||
|
`std::addressof(output)` and the stored delimiter with `std::move(delim)`.
|
||||||
|
|
||||||
|
### Member functions
|
||||||
|
|
||||||
|
```
|
||||||
|
template<class T>
|
||||||
|
ostream_joiner& operator=(const T& value);
|
||||||
|
```
|
||||||
|
|
||||||
|
[.specification]
|
||||||
|
Effects::
|
||||||
|
* If the is the first call to this member function, write the stored delimiter
|
||||||
|
to the stored stream reference.
|
||||||
|
* Writes `value` to the stored stream reference.
|
||||||
|
Returns:: `*this`.
|
||||||
|
|
||||||
|
```
|
||||||
|
ostream_joiner& operator*() noexcept;
|
||||||
|
```
|
||||||
|
```
|
||||||
|
ostream_joiner& operator++() noexcept;
|
||||||
|
```
|
||||||
|
```
|
||||||
|
ostream_joiner& operator++(int) noexcept;
|
||||||
|
```
|
||||||
|
|
||||||
|
[.specification]
|
||||||
|
Returns:: `*this`.
|
||||||
|
|
||||||
|
### Free functions
|
||||||
|
|
||||||
|
```
|
||||||
|
template<class Char, class Traits, class Delim>
|
||||||
|
ostream_joiner<decay_t<Delim>, Char, Traits>
|
||||||
|
make_ostream_joiner(std::basic_ostream<Char, Traits>& output, Delim&& delim);
|
||||||
|
```
|
||||||
|
|
||||||
|
[.specification]
|
||||||
|
Returns:: `ostream_joiner<std::decay_t<Delim>, Char, Traits>(output,
|
||||||
|
std::forward<Delim>(delim))`.
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
Glen Fernandes implemented `ostream_joiner` and `make_ostream_joiner`.
|
118
include/boost/io/ostream_joiner.hpp
Normal file
118
include/boost/io/ostream_joiner.hpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Glen Joseph Fernandes
|
||||||
|
(glenjofe@gmail.com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef BOOST_IO_OSTREAM_JOINER_HPP
|
||||||
|
#define BOOST_IO_OSTREAM_JOINER_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
|
#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
#include <utility>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace io {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX11_ADDRESSOF)
|
||||||
|
template<class T>
|
||||||
|
inline T*
|
||||||
|
osj_address(T& o)
|
||||||
|
{
|
||||||
|
return std::addressof(o);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<class T>
|
||||||
|
inline T*
|
||||||
|
osj_address(T& obj)
|
||||||
|
{
|
||||||
|
return &obj;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} /* detail */
|
||||||
|
|
||||||
|
template<class Delim, class Char = char,
|
||||||
|
class Traits = std::char_traits<Char> >
|
||||||
|
class ostream_joiner {
|
||||||
|
public:
|
||||||
|
typedef Char char_type;
|
||||||
|
typedef Traits traits_type;
|
||||||
|
typedef std::basic_ostream<Char, Traits> ostream_type;
|
||||||
|
typedef std::output_iterator_tag iterator_category;
|
||||||
|
typedef void value_type;
|
||||||
|
typedef void difference_type;
|
||||||
|
typedef void pointer;
|
||||||
|
typedef void reference;
|
||||||
|
|
||||||
|
ostream_joiner(ostream_type& output, const Delim& delim)
|
||||||
|
: output_(detail::osj_address(output))
|
||||||
|
, delim_(delim)
|
||||||
|
, first_(true) { }
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
|
ostream_joiner(ostream_type& output, Delim&& delim)
|
||||||
|
: output_(detail::osj_address(output))
|
||||||
|
, delim_(std::move(delim))
|
||||||
|
, first_(true) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
ostream_joiner& operator=(const T& value) {
|
||||||
|
if (!first_) {
|
||||||
|
*output_ << delim_;
|
||||||
|
}
|
||||||
|
first_ = false;
|
||||||
|
*output_ << value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream_joiner& operator*() BOOST_NOEXCEPT {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream_joiner& operator++() BOOST_NOEXCEPT {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream_joiner& operator++(int) BOOST_NOEXCEPT {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ostream_type* output_;
|
||||||
|
Delim delim_;
|
||||||
|
bool first_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||||
|
!defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||||
|
template<class Char, class Traits, class Delim>
|
||||||
|
inline ostream_joiner<typename std::decay<Delim>::type, Char, Traits>
|
||||||
|
make_ostream_joiner(std::basic_ostream<Char, Traits>& output, Delim&& delim)
|
||||||
|
{
|
||||||
|
return ostream_joiner<typename std::decay<Delim>::type, Char,
|
||||||
|
Traits>(output, std::forward<Delim>(delim));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<class Char, class Traits, class Delim>
|
||||||
|
inline ostream_joiner<Delim, Char, Traits>
|
||||||
|
make_ostream_joiner(std::basic_ostream<Char, Traits>& output,
|
||||||
|
const Delim& delim)
|
||||||
|
{
|
||||||
|
return ostream_joiner<Delim, Char, Traits>(output, delim);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} /* io */
|
||||||
|
} /* boost */
|
||||||
|
|
||||||
|
#endif
|
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"key": "io",
|
"key": "io",
|
||||||
"name": "IO State Savers",
|
"name": "IO",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Daryle Walker",
|
"Daryle Walker",
|
||||||
"Beman Dawes"
|
"Beman Dawes",
|
||||||
|
"Glen Fernandes"
|
||||||
],
|
],
|
||||||
"description": "Utilities for using the standard I/O library.",
|
"description": "Utilities for using the standard I/O library.",
|
||||||
"category": [
|
"category": [
|
||||||
|
@ -11,3 +11,5 @@ import testing ;
|
|||||||
run ios_state_unit_test.cpp ;
|
run ios_state_unit_test.cpp ;
|
||||||
run ios_state_test.cpp ;
|
run ios_state_test.cpp ;
|
||||||
run quoted_manip_test.cpp ;
|
run quoted_manip_test.cpp ;
|
||||||
|
run ostream_joiner_test.cpp ;
|
||||||
|
run make_ostream_joiner_test.cpp ;
|
||||||
|
21
test/make_ostream_joiner_test.cpp
Normal file
21
test/make_ostream_joiner_test.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Glen Joseph Fernandes
|
||||||
|
(glenjofe@gmail.com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
#include <boost/io/ostream_joiner.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<char> j = boost::io::make_ostream_joiner(o, ',');
|
||||||
|
*j++ = 1;
|
||||||
|
*j++ = '2';
|
||||||
|
*j++ = "3";
|
||||||
|
BOOST_TEST_EQ(o.str(), "1,2,3");
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
116
test/ostream_joiner_test.cpp
Normal file
116
test/ostream_joiner_test.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Glen Joseph Fernandes
|
||||||
|
(glenjofe@gmail.com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <boost/io/ostream_joiner.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
void test_char_type()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(char,
|
||||||
|
boost::io::ostream_joiner<const char*>::char_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_traits_type()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(std::char_traits<char>,
|
||||||
|
boost::io::ostream_joiner<const char*>::traits_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ostream_type()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(std::ostream,
|
||||||
|
boost::io::ostream_joiner<const char*>::ostream_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_iterator_category()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(std::output_iterator_tag,
|
||||||
|
boost::io::ostream_joiner<const char*>::iterator_category);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_value_type()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(void,
|
||||||
|
boost::io::ostream_joiner<const char*>::value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_difference_type()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(void,
|
||||||
|
boost::io::ostream_joiner<const char*>::difference_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_pointer()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(void,
|
||||||
|
boost::io::ostream_joiner<const char*>::pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_reference()
|
||||||
|
{
|
||||||
|
BOOST_TEST_TRAIT_SAME(void,
|
||||||
|
boost::io::ostream_joiner<const char*>::reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_construct()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<const char*> j(o, ",");
|
||||||
|
BOOST_TEST(o.str().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_assign()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<const char*> j(o, ",");
|
||||||
|
j = 1;
|
||||||
|
BOOST_TEST_EQ(o.str(), "1");
|
||||||
|
j = '2';
|
||||||
|
BOOST_TEST_EQ(o.str(), "1,2");
|
||||||
|
j = "3";
|
||||||
|
BOOST_TEST_EQ(o.str(), "1,2,3");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_increment()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<const char*> j(o, ",");
|
||||||
|
BOOST_TEST_EQ(&++j, &j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_post_increment()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<const char*> j(o, ",");
|
||||||
|
BOOST_TEST_EQ(&j++, &j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_value()
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
boost::io::ostream_joiner<const char*> j(o, ",");
|
||||||
|
BOOST_TEST_EQ(&*j, &j);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
test_char_type();
|
||||||
|
test_traits_type();
|
||||||
|
test_ostream_type();
|
||||||
|
test_iterator_category();
|
||||||
|
test_value_type();
|
||||||
|
test_difference_type();
|
||||||
|
test_pointer();
|
||||||
|
test_reference();
|
||||||
|
test_construct();
|
||||||
|
test_assign();
|
||||||
|
test_increment();
|
||||||
|
test_post_increment();
|
||||||
|
test_value();
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
Reference in New Issue
Block a user