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

@ -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);
}