diff --git a/doc/io-docinfo-footer.html b/doc/io-docinfo-footer.html new file mode 100644 index 0000000..1fcafdc --- /dev/null +++ b/doc/io-docinfo-footer.html @@ -0,0 +1,5 @@ + diff --git a/doc/io.adoc b/doc/io.adoc index 6685efe..b8f0c2f 100644 --- a/doc/io.adoc +++ b/doc/io.adoc @@ -7,7 +7,8 @@ Distributed under the Boost Software License, Version 1.0. //// # Boost.IO -Daryle Walker, Beman Dawes +Daryle Walker, Beman Dawes, Glen Joseph Fernandes +:docinfo: private-footer :idprefix: :source-language: cpp :toc: left @@ -19,6 +20,7 @@ library. :leveloffset: +1 include::ios_state.adoc[] +include::ostream_joiner.adoc[] :leveloffset: -1 diff --git a/doc/ostream_joiner.adoc b/doc/ostream_joiner.adoc new file mode 100644 index 0000000..4a98cbf --- /dev/null +++ b/doc/ostream_joiner.adoc @@ -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, +:toc: +:toc-title: +:idprefix: + +## Description + +The header `` 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 +#include +#include +#include + +int main() +{ + std::vector 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 ostream_joiner { +public: + typedef Char char_type; + typedef Traits traits_type; + typedef std::basic_ostream 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 + ostream_joiner& operator=(const T& value); + + ostream_joiner& operator*() noexcept; + ostream_joiner& operator++() noexcept; + ostream_joiner& operator++(int) noexcept; +}; + +template +ostream_joiner, Char, Traits> +make_ostream_joiner(std::basic_ostream& 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 +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 +ostream_joiner, Char, Traits> +make_ostream_joiner(std::basic_ostream& output, Delim&& delim); +``` + +[.specification] +Returns:: `ostream_joiner, Char, Traits>(output, +std::forward(delim))`. + +## Acknowledgments + +Glen Fernandes implemented `ostream_joiner` and `make_ostream_joiner`. diff --git a/include/boost/io/ostream_joiner.hpp b/include/boost/io/ostream_joiner.hpp new file mode 100644 index 0000000..a771521 --- /dev/null +++ b/include/boost/io/ostream_joiner.hpp @@ -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 +#include +#include +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#endif +#include +#endif + +namespace boost { +namespace io { +namespace detail { + +#if !defined(BOOST_NO_CXX11_ADDRESSOF) +template +inline T* +osj_address(T& o) +{ + return std::addressof(o); +} +#else +template +inline T* +osj_address(T& obj) +{ + return &obj; +} +#endif + +} /* detail */ + +template > +class ostream_joiner { +public: + typedef Char char_type; + typedef Traits traits_type; + typedef std::basic_ostream 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 + 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 +inline ostream_joiner::type, Char, Traits> +make_ostream_joiner(std::basic_ostream& output, Delim&& delim) +{ + return ostream_joiner::type, Char, + Traits>(output, std::forward(delim)); +} +#else +template +inline ostream_joiner +make_ostream_joiner(std::basic_ostream& output, + const Delim& delim) +{ + return ostream_joiner(output, delim); +} +#endif + +} /* io */ +} /* boost */ + +#endif diff --git a/meta/libraries.json b/meta/libraries.json index 3259e18..42ad3af 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -1,9 +1,10 @@ { "key": "io", - "name": "IO State Savers", + "name": "IO", "authors": [ "Daryle Walker", - "Beman Dawes" + "Beman Dawes", + "Glen Fernandes" ], "description": "Utilities for using the standard I/O library.", "category": [ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8d12343..ed68f5a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,3 +11,5 @@ import testing ; run ios_state_unit_test.cpp ; run ios_state_test.cpp ; run quoted_manip_test.cpp ; +run ostream_joiner_test.cpp ; +run make_ostream_joiner_test.cpp ; diff --git a/test/make_ostream_joiner_test.cpp b/test/make_ostream_joiner_test.cpp new file mode 100644 index 0000000..d262f69 --- /dev/null +++ b/test/make_ostream_joiner_test.cpp @@ -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 +#include +#include + +int main() +{ + std::ostringstream o; + boost::io::ostream_joiner 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(); +} diff --git a/test/ostream_joiner_test.cpp b/test/ostream_joiner_test.cpp new file mode 100644 index 0000000..aa1ea44 --- /dev/null +++ b/test/ostream_joiner_test.cpp @@ -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 +#include +#include + +void test_char_type() +{ + BOOST_TEST_TRAIT_SAME(char, + boost::io::ostream_joiner::char_type); +} + +void test_traits_type() +{ + BOOST_TEST_TRAIT_SAME(std::char_traits, + boost::io::ostream_joiner::traits_type); +} + +void test_ostream_type() +{ + BOOST_TEST_TRAIT_SAME(std::ostream, + boost::io::ostream_joiner::ostream_type); +} + +void test_iterator_category() +{ + BOOST_TEST_TRAIT_SAME(std::output_iterator_tag, + boost::io::ostream_joiner::iterator_category); +} + +void test_value_type() +{ + BOOST_TEST_TRAIT_SAME(void, + boost::io::ostream_joiner::value_type); +} + +void test_difference_type() +{ + BOOST_TEST_TRAIT_SAME(void, + boost::io::ostream_joiner::difference_type); +} + +void test_pointer() +{ + BOOST_TEST_TRAIT_SAME(void, + boost::io::ostream_joiner::pointer); +} + +void test_reference() +{ + BOOST_TEST_TRAIT_SAME(void, + boost::io::ostream_joiner::reference); +} + +void test_construct() +{ + std::ostringstream o; + boost::io::ostream_joiner j(o, ","); + BOOST_TEST(o.str().empty()); +} + +void test_assign() +{ + std::ostringstream o; + boost::io::ostream_joiner 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 j(o, ","); + BOOST_TEST_EQ(&++j, &j); +} + +void test_post_increment() +{ + std::ostringstream o; + boost::io::ostream_joiner j(o, ","); + BOOST_TEST_EQ(&j++, &j); +} + +void test_value() +{ + std::ostringstream o; + boost::io::ostream_joiner 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(); +}