Support stream width and fill and write directly to stream buffer

This commit is contained in:
Glen Fernandes
2020-04-09 01:26:14 -04:00
parent 9f8765e752
commit c8ce84089b
5 changed files with 249 additions and 34 deletions

View File

@ -140,3 +140,6 @@ for the name and form of the templates.
Beman Dawes started the implementation of `quoted()` as a private detail
header. Glen Fernandes updated the implementation and also made it public.
Glen Fernandes corrected the implementation to properly account for stream
width and fill, and optimized it to write directly to the stream buffer.

View File

@ -1,7 +1,7 @@
/*
Copyright 2010 Beman Dawes
Copyright 2019 Glen Joseph Fernandes
Copyright 2019-2020 Glen Joseph Fernandes
(glenjofe@gmail.com)
Distributed under the Boost Software License, Version 1.0.
@ -10,10 +10,9 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef BOOST_IO_QUOTED_HPP
#define BOOST_IO_QUOTED_HPP
#include <boost/io/detail/buffer_fill.hpp>
#include <boost/io/detail/ostream_guard.hpp>
#include <boost/io/ios_state.hpp>
#include <ios>
#include <iterator>
#include <string>
namespace boost {
namespace io {
@ -26,37 +25,113 @@ struct quoted_proxy {
Char delim;
};
template<class Char>
struct quoted_state {
const Char* string;
std::size_t size;
std::size_t count;
};
template<class Char>
inline quoted_state<Char>
quoted_start(const Char* string, Char escape, Char delim)
{
const Char* end = string;
std::size_t count = 2;
for (Char ch; (ch = *end) != 0; ++end) {
count += 1 + (ch == escape || ch == delim);
}
quoted_state<Char> state = { string,
static_cast<std::size_t>(end - string), count };
return state;
}
template<class Char, class String>
inline quoted_state<Char>
quoted_start(const String* string, Char escape, Char delim)
{
const Char* begin = string->data();
std::size_t size = string->size();
std::size_t count = 2;
for (const Char *it = begin, *end = begin + size; it != end; ++it) {
Char ch = *it;
count += 1 + (ch == escape || ch == delim);
}
quoted_state<Char> state = { begin, size, count };
return state;
}
template<class Char, class Traits>
inline bool
quoted_put(std::basic_streambuf<Char, Traits>& buf, const Char* string,
std::size_t size, std::size_t count, Char escape, Char delim)
{
if (buf.sputc(delim) == Traits::eof()) {
return false;
}
if (size == count) {
if (static_cast<std::size_t>(buf.sputn(string, size)) != size) {
return false;
}
} else {
for (const Char* end = string + size; string != end; ++string) {
Char ch = *string;
if ((ch == escape || ch == delim) &&
buf.sputc(escape) == Traits::eof()) {
return false;
}
if (buf.sputc(ch) == Traits::eof()) {
return false;
}
}
}
return buf.sputc(delim) != Traits::eof();
}
template<class Char, class Traits, class String>
inline std::basic_ostream<Char, Traits>&
quoted_out(std::basic_ostream<Char, Traits>& os, String* string, Char escape,
Char delim)
{
typedef std::basic_ostream<Char, Traits> stream;
ostream_guard<Char, Traits> guard(os);
typename stream::sentry entry(os);
if (entry) {
quoted_state<Char> state = boost::io::detail::quoted_start(string,
escape, delim);
std::basic_streambuf<Char, Traits>& buf = *os.rdbuf();
std::size_t width = static_cast<std::size_t>(os.width());
if (width <= state.count) {
if (!boost::io::detail::quoted_put(buf, state.string, state.size,
state.count, escape, delim)) {
return os;
}
} else if ((os.flags() & stream::adjustfield) == stream::left) {
if (!boost::io::detail::quoted_put(buf, state.string, state.size,
state.count, escape, delim) ||
!boost::io::detail::buffer_fill(buf, os.fill(),
width - state.count)) {
return os;
}
} else if (!boost::io::detail::buffer_fill(buf, os.fill(),
width - state.count) ||
!boost::io::detail::quoted_put(buf, state.string, state.size,
state.count, escape, delim)) {
return os;
}
os.width(0);
}
guard.release();
return os;
}
template<class Char, class Traits>
inline std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& os,
const quoted_proxy<const Char*, Char>& proxy)
{
os.put(proxy.delim);
for (const Char* it = proxy.string; *it; ++it) {
if (*it == proxy.delim || *it == proxy.escape) {
os.put(proxy.escape);
}
os.put(*it);
}
return os.put(proxy.delim);
}
template<class Char, class Traits, class Alloc>
inline std::basic_ostream<Char, Traits>&
quoted_output(std::basic_ostream<Char, Traits>& os,
const std::basic_string<Char, Traits, Alloc>& string, Char escape,
Char delim)
{
os.put(delim);
for (typename std::basic_string<Char, Traits,
Alloc>::const_iterator it = string.begin(), end = string.end();
it != end; ++it) {
if (*it == delim || *it == escape) {
os.put(escape);
}
os.put(*it);
}
return os.put(delim);
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
proxy.delim);
}
template <class Char, class Traits, class Alloc>
@ -65,7 +140,7 @@ operator<<(std::basic_ostream<Char, Traits>& os,
const quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
Char>& proxy)
{
return boost::io::detail::quoted_output(os, *proxy.string, proxy.escape,
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
proxy.delim);
}
@ -74,7 +149,7 @@ inline std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& os,
const quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>& proxy)
{
return boost::io::detail::quoted_output(os, *proxy.string, proxy.escape,
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
proxy.delim);
}

View File

@ -13,6 +13,7 @@ project : requirements <warnings>pedantic <warnings-as-errors>on ;
run ios_state_unit_test.cpp ;
run ios_state_test.cpp ;
run quoted_test.cpp ;
run quoted_fill_test.cpp ;
run ostream_joiner_test.cpp ;
run make_ostream_joiner_test.cpp ;
run ostream_put_test.cpp ;

View File

@ -25,7 +25,7 @@ int main()
{
std::wostringstream os;
os.width(1);
os.fill('.');
os.fill(L'.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
boost::io::ostream_put(os, L"xy", 2);
BOOST_TEST(os.good());
@ -45,7 +45,7 @@ int main()
{
std::wostringstream os;
os.width(1);
os.fill('.');
os.fill(L'.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
boost::io::ostream_put(os, L"xy", 2);
BOOST_TEST(os.good());

136
test/quoted_fill_test.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
Copyright 2019-2020 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/io/quoted.hpp>
#include <boost/core/lightweight_test.hpp>
#include <sstream>
#include <string>
int main()
{
{
std::ostringstream os;
os.width(2);
os.fill('.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "\"xy\"");
}
{
std::wostringstream os;
os.width(2);
os.fill(L'.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"\"xy\"");
}
{
std::ostringstream os;
os.width(2);
os.fill('.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "\"xy\"");
}
{
std::wostringstream os;
os.width(2);
os.fill(L'.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"\"xy\"");
}
{
std::ostringstream os;
os.width(6);
os.fill('.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "\"xy\"..");
}
{
std::wostringstream os;
os.width(6);
os.fill(L'.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"\"xy\"..");
}
{
std::ostringstream os;
os.width(6);
os.fill('.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "..\"xy\"");
}
{
std::wostringstream os;
os.width(6);
os.fill(L'.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"..\"xy\"");
}
{
std::ostringstream os;
os.width(14);
os.fill('.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "\"xy\"..........");
}
{
std::wostringstream os;
os.width(14);
os.fill(L'.');
os.setf(std::ios_base::left, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"\"xy\"..........");
}
{
std::ostringstream os;
os.width(14);
os.fill('.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted("xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == "..........\"xy\"");
}
{
std::wostringstream os;
os.width(14);
os.fill(L'.');
os.setf(std::ios_base::right, std::ios_base::adjustfield);
os << boost::io::quoted(L"xy");
BOOST_TEST(os.good());
BOOST_TEST(os.width() == 0);
BOOST_TEST(os.str() == L"..........\"xy\"");
}
return boost::report_errors();
}