diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2
index dda8f39..b2d5229 100644
--- a/doc/Jamfile.v2
+++ b/doc/Jamfile.v2
@@ -99,6 +99,19 @@ boostbook standalone_declval
generate.section.toc.level=1
;
+xml ostream_string : ostream_string.qbk ;
+boostbook standalone_ostream_string
+ :
+ ostream_string
+ :
+ root.filename=ostream_string
+ chunk.section.depth=0
+ chunk.first.sections=0
+ toc.section.depth=1
+ toc.max.depth=1
+ generate.section.toc.level=1
+ ;
+
xml string_ref : string_ref.qbk ;
boostbook standalone_string_ref
:
@@ -123,5 +136,5 @@ alias boostdoc ;
explicit boostdoc ;
alias boostrelease :
standalone_base_from_member standalone_compressed_pair
- standalone_declval standalone_string_ref ;
+ standalone_declval standalone_ostream_string standalone_string_ref ;
explicit boostrelease ;
diff --git a/doc/ostream_string.qbk b/doc/ostream_string.qbk
new file mode 100644
index 0000000..a99ad0c
--- /dev/null
+++ b/doc/ostream_string.qbk
@@ -0,0 +1,62 @@
+[/
+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)
+]
+
+[article ostream_string
+[quickbook 1.5]
+[authors [Fernandes, Glen]]
+[copyright 2019 Glen Joseph Fernandes]
+[license Distributed under the Boost Software License, Version 1.0.]]
+
+[section Overview]
+
+The header provides the function template
+boost::ostream_string for formatted output that satisfies the requirements of
+\[ostream.formatted.reqmts\].
+
+[endsect]
+
+[section Examples]
+
+The inserter for class template `basic_string_view` could be implemented as
+follows:
+
+```
+template
+std::basic_ostream&
+operator<<(std::basic_ostream& os,
+ const basic_string_view& str)
+{
+ return boost::ostream_string(os, str.data(), str.size());
+}
+```
+
+[endsect]
+
+[section Reference]
+
+```
+namespace boost {
+
+template
+std::basic_ostream&
+ostream_string(std::basic_ostream& os,
+ const charT* data, std::size_t size);
+
+} /* boost */
+```
+
+[variablelist
+[[Effects]
+[Behaves like a formatted inserter (as described in
+\[ostream.formatted.reqmts\]) of `os`. Creates a character sequence `seq` of
+`size` characters starting at `data`, each widened using `os.widen()`
+(\[basic.ios.members\]). Determines padding for `seq` as described in
+\[ostream.formatted.reqmts\]. Inserts `seq` into `os`. Calls `width(0)`.]]
+[[Returns] [`os`.]]]
+
+[endsect]
diff --git a/include/boost/utility/ostream_string.hpp b/include/boost/utility/ostream_string.hpp
new file mode 100644
index 0000000..8722e58
--- /dev/null
+++ b/include/boost/utility/ostream_string.hpp
@@ -0,0 +1,95 @@
+/*
+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_UTILITY_OSTREAM_STRING_HPP
+#define BOOST_UTILITY_OSTREAM_STRING_HPP
+
+#include
+#include
+#include
+
+namespace boost {
+namespace detail {
+
+template
+inline std::size_t
+oss_put(std::basic_ostream& os, const charT* data,
+ std::size_t size)
+{
+ return static_cast(os.rdbuf()->sputn(data, size));
+}
+
+template
+inline bool
+oss_fill(std::basic_ostream& os, std::size_t size)
+{
+ charT c = os.fill();
+ charT fill[] = { c, c, c, c, c, c, c, c };
+ enum {
+ chunk = sizeof fill / sizeof(charT)
+ };
+ for (; size > chunk; size -= chunk) {
+ if (boost::detail::oss_put(os, fill, chunk) != chunk) {
+ return false;
+ }
+ }
+ return boost::detail::oss_put(os, fill, size) == size;
+}
+
+template
+class oss_guard {
+public:
+ explicit oss_guard(std::basic_ostream& os) BOOST_NOEXCEPT
+ : os_(&os) { }
+ ~oss_guard() BOOST_NOEXCEPT_IF(false) {
+ if (os_) {
+ os_->setstate(std::basic_ostream::badbit);
+ }
+ }
+ void release() BOOST_NOEXCEPT {
+ os_ = 0;
+ }
+private:
+ oss_guard(const oss_guard&);
+ oss_guard& operator=(const oss_guard&);
+ std::basic_ostream* os_;
+};
+
+} /* detail */
+
+template
+inline std::basic_ostream&
+ostream_string(std::basic_ostream& os, const charT* data,
+ std::size_t size)
+{
+ typedef std::basic_ostream stream;
+ detail::oss_guard guard(os);
+ typename stream::sentry entry(os);
+ if (entry) {
+ std::size_t width = static_cast(os.width());
+ if (width <= size) {
+ if (detail::oss_put(os, data, size) != size) {
+ return os;
+ }
+ } else if ((os.flags() & stream::adjustfield) == stream::left) {
+ if (detail::oss_put(os, data, size) != size ||
+ !detail::oss_fill(os, width - size)) {
+ return os;
+ }
+ } else if (!detail::oss_fill(os, width - size) ||
+ detail::oss_put(os, data, size) != size) {
+ return os;
+ }
+ os.width(0);
+ }
+ guard.release();
+ return os;
+}
+
+} /* boost */
+
+#endif
diff --git a/include/boost/utility/string_ref.hpp b/include/boost/utility/string_ref.hpp
index 36f4fc8..999f1c3 100644
--- a/include/boost/utility/string_ref.hpp
+++ b/include/boost/utility/string_ref.hpp
@@ -18,6 +18,7 @@
#include
#include
+#include
#include
#include
@@ -422,76 +423,11 @@ namespace boost {
return basic_string_ref(x) >= y;
}
- namespace detail {
-
- template
- inline std::size_t sr_os_put(std::basic_ostream& os,
- const charT* data, std::size_t size) {
- return static_cast(os.rdbuf()->sputn(data, size));
- }
-
- template
- inline bool sr_os_fill(std::basic_ostream& os,
- std::size_t size) {
- enum { chunk = 8 };
- charT fill[chunk];
- std::fill_n(fill, static_cast(chunk), os.fill());
- for (; size > chunk; size -= chunk) {
- if (detail::sr_os_put(os, fill, chunk) != chunk) {
- return false;
- }
- }
- return detail::sr_os_put(os, fill, size) == size;
- }
-
- template
- class sr_os_holder {
- public:
- explicit sr_os_holder(std::basic_ostream& os)
- : os_(&os) { }
- ~sr_os_holder() BOOST_NOEXCEPT_IF(false) {
- if (os_) {
- os_->setstate(std::basic_ostream::badbit);
- }
- }
- void release() {
- os_ = 0;
- }
- private:
- sr_os_holder(const sr_os_holder&);
- sr_os_holder& operator=(const sr_os_holder&);
- std::basic_ostream* os_;
- };
-
- } // namespace detail
-
// Inserter
template
inline std::basic_ostream&
operator<<(std::basic_ostream& os, const basic_string_ref& str) {
- typedef std::basic_ostream stream;
- detail::sr_os_holder hold(os);
- typename stream::sentry entry(os);
- if (entry) {
- std::size_t width = static_cast(os.width());
- std::size_t size = str.size();
- if (width <= size) {
- if (detail::sr_os_put(os, str.data(), size) != size) {
- return os;
- }
- } else if ((os.flags() & stream::adjustfield) == stream::left) {
- if (detail::sr_os_put(os, str.data(), size) != size ||
- !detail::sr_os_fill(os, width - size)) {
- return os;
- }
- } else if (!detail::sr_os_fill(os, width - size) ||
- detail::sr_os_put(os, str.data(), size) != size) {
- return os;
- }
- os.width(0);
- }
- hold.release();
- return os;
+ return boost::ostream_string(os, str.data(), str.size());
}
#if 0
diff --git a/include/boost/utility/string_view.hpp b/include/boost/utility/string_view.hpp
index 5cab012..1677e9f 100644
--- a/include/boost/utility/string_view.hpp
+++ b/include/boost/utility/string_view.hpp
@@ -20,6 +20,7 @@
#include
#include
+#include
#include
#include
#include
@@ -572,77 +573,12 @@ namespace boost {
return basic_string_view(x) >= y;
}
- namespace detail {
-
- template
- inline std::size_t sv_os_put(std::basic_ostream& os,
- const charT* data, std::size_t size) {
- return static_cast(os.rdbuf()->sputn(data, size));
- }
-
- template
- inline bool sv_os_fill(std::basic_ostream& os,
- std::size_t size) {
- enum { chunk = 8 };
- charT fill[chunk];
- std::fill_n(fill, static_cast(chunk), os.fill());
- for (; size > chunk; size -= chunk) {
- if (detail::sv_os_put(os, fill, chunk) != chunk) {
- return false;
- }
- }
- return detail::sv_os_put(os, fill, size) == size;
- }
-
- template
- class sv_os_holder {
- public:
- explicit sv_os_holder(std::basic_ostream& os)
- : os_(&os) { }
- ~sv_os_holder() BOOST_NOEXCEPT_IF(false) {
- if (os_) {
- os_->setstate(std::basic_ostream::badbit);
- }
- }
- void release() {
- os_ = 0;
- }
- private:
- sv_os_holder(const sv_os_holder&);
- sv_os_holder& operator=(const sv_os_holder&);
- std::basic_ostream* os_;
- };
-
- } // namespace detail
-
// Inserter
template
inline std::basic_ostream&
operator<<(std::basic_ostream& os,
const basic_string_view& str) {
- typedef std::basic_ostream stream;
- detail::sv_os_holder hold(os);
- typename stream::sentry entry(os);
- if (entry) {
- std::size_t width = static_cast(os.width());
- std::size_t size = str.size();
- if (width <= size) {
- if (detail::sv_os_put(os, str.data(), size) != size) {
- return os;
- }
- } else if ((os.flags() & stream::adjustfield) == stream::left) {
- if (detail::sv_os_put(os, str.data(), size) != size ||
- !detail::sv_os_fill(os, width - size)) {
- return os;
- }
- } else if (!detail::sv_os_fill(os, width - size) ||
- detail::sv_os_put(os, str.data(), size) != size) {
- return os;
- }
- os.width(0);
- }
- hold.release();
- return os;
+ return boost::ostream_string(os, str.data(), str.size());
}
#if 0
diff --git a/index.html b/index.html
index 57fa56f..7dcdd64 100644
--- a/index.html
+++ b/index.html
@@ -31,6 +31,7 @@
result_of
throw_exception
utility
+ ostream_string
string_ref
value_init
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 739edc0..d0277ef 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -42,3 +42,5 @@ compile-fail value_init_test_fail2.cpp ;
compile-fail value_init_test_fail3.cpp ;
compile-fail initialized_test_fail1.cpp ;
compile-fail initialized_test_fail2.cpp ;
+
+run ostream_string_test.cpp ;
diff --git a/test/ostream_string_test.cpp b/test/ostream_string_test.cpp
new file mode 100644
index 0000000..e6145b3
--- /dev/null
+++ b/test/ostream_string_test.cpp
@@ -0,0 +1,136 @@
+/*
+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
+#include
+
+int main()
+{
+ {
+ std::ostringstream os;
+ os.width(1);
+ os.fill('.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "xy");
+ }
+ {
+ std::wostringstream os;
+ os.width(1);
+ os.fill('.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"xy");
+ }
+ {
+ std::ostringstream os;
+ os.width(1);
+ os.fill('.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "xy");
+ }
+ {
+ std::wostringstream os;
+ os.width(1);
+ os.fill('.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"xy");
+ }
+ {
+ std::ostringstream os;
+ os.width(4);
+ os.fill('.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "xy..");
+ }
+ {
+ std::wostringstream os;
+ os.width(4);
+ os.fill(L'.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"xy..");
+ }
+ {
+ std::ostringstream os;
+ os.width(4);
+ os.fill('.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "..xy");
+ }
+ {
+ std::wostringstream os;
+ os.width(4);
+ os.fill(L'.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"..xy");
+ }
+ {
+ std::ostringstream os;
+ os.width(12);
+ os.fill('.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "xy..........");
+ }
+ {
+ std::wostringstream os;
+ os.width(12);
+ os.fill(L'.');
+ os.setf(std::ios_base::left, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"xy..........");
+ }
+ {
+ std::ostringstream os;
+ os.width(12);
+ os.fill('.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, "xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == "..........xy");
+ }
+ {
+ std::wostringstream os;
+ os.width(12);
+ os.fill(L'.');
+ os.setf(std::ios_base::right, std::ios_base::adjustfield);
+ boost::ostream_string(os, L"xy", 2);
+ BOOST_TEST(os.good());
+ BOOST_TEST(os.width() == 0);
+ BOOST_TEST(os.str() == L"..........xy");
+ }
+ return boost::report_errors();
+}