Merge branch 'develop'

This commit is contained in:
Glen Fernandes
2020-04-10 16:13:22 -04:00
9 changed files with 352 additions and 108 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

@ -0,0 +1,39 @@
/*
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)
*/
#ifndef BOOST_IO_DETAIL_BUFFER_FILL_HPP
#define BOOST_IO_DETAIL_BUFFER_FILL_HPP
#include <iosfwd>
#include <cstddef>
namespace boost {
namespace io {
namespace detail {
template<class charT, class traits>
inline bool
buffer_fill(std::basic_streambuf<charT, traits>& buf, charT ch,
std::size_t size)
{
charT fill[] = { ch, ch, ch, ch, ch, ch, ch, ch };
enum {
chunk = sizeof fill / sizeof(charT)
};
for (; size > chunk; size -= chunk) {
if (static_cast<std::size_t>(buf.sputn(fill, chunk)) != chunk) {
return false;
}
}
return static_cast<std::size_t>(buf.sputn(fill, size)) == size;
}
} /* detail */
} /* io */
} /* boost */
#endif

View File

@ -0,0 +1,45 @@
/*
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)
*/
#ifndef BOOST_IO_DETAIL_OSTREAM_GUARD_HPP
#define BOOST_IO_DETAIL_OSTREAM_GUARD_HPP
#include <boost/config.hpp>
#include <iosfwd>
namespace boost {
namespace io {
namespace detail {
template<class Char, class Traits>
class ostream_guard {
public:
explicit ostream_guard(std::basic_ostream<Char, Traits>& os) BOOST_NOEXCEPT
: os_(&os) { }
~ostream_guard() BOOST_NOEXCEPT_IF(false) {
if (os_) {
os_->setstate(std::basic_ostream<Char, Traits>::badbit);
}
}
void release() BOOST_NOEXCEPT {
os_ = 0;
}
private:
ostream_guard(const ostream_guard&);
ostream_guard& operator=(const ostream_guard&);
std::basic_ostream<Char, Traits>* os_;
};
} /* detail */
} /* io */
} /* boost */
#endif

View File

@ -7,8 +7,8 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef BOOST_IO_IOS_STATE_HPP
#define BOOST_IO_IOS_STATE_HPP
#include <boost/config.hpp>
#include <boost/io_fwd.hpp>
#include <boost/config/workaround.hpp>
#include <ios>
#ifndef BOOST_NO_STD_LOCALE
#include <locale>
@ -29,7 +29,7 @@ public:
: s_save_(s)
, a_save_(s.flags()) { }
ios_flags_saver(state_type& s, const aspect_type& a)
ios_flags_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.flags(a)) { }
@ -58,7 +58,7 @@ public:
: s_save_(s)
, a_save_(s.precision()) { }
ios_precision_saver(state_type& s, const aspect_type& a)
ios_precision_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.precision(a)) { }
@ -87,7 +87,7 @@ public:
: s_save_(s)
, a_save_(s.width()) { }
ios_width_saver(state_type& s, const aspect_type& a)
ios_width_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.width(a)) { }
@ -117,7 +117,7 @@ public:
: s_save_(s)
, a_save_(s.rdstate()) { }
basic_ios_iostate_saver(state_type& s, const aspect_type& a)
basic_ios_iostate_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.rdstate()) {
s.clear(a);
@ -149,11 +149,7 @@ public:
: s_save_(s)
, a_save_(s.exceptions()) { }
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
basic_ios_exception_saver(state_type& s, aspect_type a)
#else
basic_ios_exception_saver(state_type& s, const aspect_type& a)
#endif
: s_save_(s)
, a_save_(s.exceptions()) {
s.exceptions(a);
@ -185,7 +181,7 @@ public:
: s_save_(s)
, a_save_(s.tie()) { }
basic_ios_tie_saver(state_type& s, const aspect_type& a)
basic_ios_tie_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.tie(a)) { }
@ -215,7 +211,7 @@ public:
: s_save_(s)
, a_save_(s.rdbuf()) { }
basic_ios_rdbuf_saver(state_type& s, const aspect_type& a)
basic_ios_rdbuf_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.rdbuf(a)) { }
@ -245,7 +241,7 @@ public:
: s_save_(s)
, a_save_(s.fill()) { }
basic_ios_fill_saver(state_type& s, const aspect_type& a)
basic_ios_fill_saver(state_type& s, aspect_type a)
: s_save_(s)
, a_save_(s.fill(a)) { }
@ -308,7 +304,7 @@ public:
, a_save_(s.iword(i))
, i_save_(i) { }
ios_iword_saver(state_type& s, index_type i, const aspect_type& a)
ios_iword_saver(state_type& s, index_type i, aspect_type a)
: s_save_(s)
, a_save_(s.iword(i))
, i_save_(i) {
@ -343,7 +339,7 @@ public:
, a_save_(s.pword(i))
, i_save_(i) { }
ios_pword_saver(state_type& s, index_type i, const aspect_type& a)
ios_pword_saver(state_type& s, index_type i, aspect_type a)
: s_save_(s)
, a_save_(s.pword(i))
, i_save_(i) {

View File

@ -8,62 +8,11 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef BOOST_IO_OSTREAM_PUT_HPP
#define BOOST_IO_OSTREAM_PUT_HPP
#include <boost/config.hpp>
#include <iosfwd>
#include <cstddef>
#include <boost/io/detail/buffer_fill.hpp>
#include <boost/io/detail/ostream_guard.hpp>
namespace boost {
namespace io {
namespace detail {
template<class charT, class traits>
inline std::size_t
osp_put(std::basic_streambuf<charT, traits>& out, const charT* data,
std::size_t size)
{
return static_cast<std::size_t>(out.sputn(data, size));
}
template<class charT, class traits>
inline bool
osp_fill(std::basic_streambuf<charT, traits>& out, charT c, std::size_t size)
{
charT fill[] = { c, c, c, c, c, c, c, c };
enum {
chunk = sizeof fill / sizeof(charT)
};
for (; size > chunk; size -= chunk) {
if (boost::io::detail::osp_put(out, fill, chunk) != chunk) {
return false;
}
}
return boost::io::detail::osp_put(out, fill, size) == size;
}
template<class charT, class traits>
class osp_guard {
public:
explicit osp_guard(std::basic_ostream<charT, traits>& os) BOOST_NOEXCEPT
: os_(&os) { }
~osp_guard() BOOST_NOEXCEPT_IF(false) {
if (os_) {
os_->setstate(std::basic_ostream<charT, traits>::badbit);
}
}
void release() BOOST_NOEXCEPT {
os_ = 0;
}
private:
osp_guard(const osp_guard&);
osp_guard& operator=(const osp_guard&);
std::basic_ostream<charT, traits>* os_;
};
} /* detail */
template<class charT, class traits>
inline std::basic_ostream<charT, traits>&
@ -71,22 +20,22 @@ ostream_put(std::basic_ostream<charT, traits>& os, const charT* data,
std::size_t size)
{
typedef std::basic_ostream<charT, traits> stream;
detail::osp_guard<charT, traits> guard(os);
detail::ostream_guard<charT, traits> guard(os);
typename stream::sentry entry(os);
if (entry) {
std::basic_streambuf<charT, traits>& out = *os.rdbuf();
std::basic_streambuf<charT, traits>& buf = *os.rdbuf();
std::size_t width = static_cast<std::size_t>(os.width());
if (width <= size) {
if (detail::osp_put(out, data, size) != size) {
if (static_cast<std::size_t>(buf.sputn(data, size)) != size) {
return os;
}
} else if ((os.flags() & stream::adjustfield) == stream::left) {
if (detail::osp_put(out, data, size) != size ||
!detail::osp_fill(out, os.fill(), width - size)) {
if (static_cast<std::size_t>(buf.sputn(data, size)) != size ||
!detail::buffer_fill(buf, os.fill(), width - size)) {
return os;
}
} else if (!detail::osp_fill(out, os.fill(), width - size) ||
detail::osp_put(out, data, size) != size) {
} else if (!detail::buffer_fill(buf, os.fill(), width - size) ||
static_cast<std::size_t>(buf.sputn(data, size)) != size) {
return os;
}
os.width(0);

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