Add string_param

fix #451
This commit is contained in:
Vinnie Falco
2017-06-10 15:56:48 -07:00
parent 49a2b33b82
commit 0d70d90b75
8 changed files with 310 additions and 1 deletions

View File

@ -5,6 +5,7 @@ Version 54:
* multi_buffer coverage * multi_buffer coverage
* consuming_buffers members and coverage * consuming_buffers members and coverage
* basic_fields members and coverage * basic_fields members and coverage
* Add string_param
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -177,6 +177,7 @@
<member><link linkend="beast.ref.static_buffer">static_buffer</link></member> <member><link linkend="beast.ref.static_buffer">static_buffer</link></member>
<member><link linkend="beast.ref.static_buffer_n">static_buffer_n</link></member> <member><link linkend="beast.ref.static_buffer_n">static_buffer_n</link></member>
<member><link linkend="beast.ref.static_string">static_string</link></member> <member><link linkend="beast.ref.static_string">static_string</link></member>
<member><link linkend="beast.ref.string_param">string_param</link></member>
<member><link linkend="beast.ref.string_view">string_view</link></member> <member><link linkend="beast.ref.string_view">string_view</link></member>
<member><link linkend="beast.ref.system_error">system_error</link></member> <member><link linkend="beast.ref.system_error">system_error</link></member>
</simplelist> </simplelist>

View File

@ -14,9 +14,10 @@
#include <beast/core/bind_handler.hpp> #include <beast/core/bind_handler.hpp>
#include <beast/core/buffer_cat.hpp> #include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_prefix.hpp> #include <beast/core/buffer_prefix.hpp>
#include <beast/core/buffered_read_stream.hpp>
#include <beast/core/buffers_adapter.hpp> #include <beast/core/buffers_adapter.hpp>
#include <beast/core/consuming_buffers.hpp> #include <beast/core/consuming_buffers.hpp>
#include <beast/core/buffered_read_stream.hpp> #include <beast/core/drain_buffer.hpp>
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <beast/core/flat_buffer.hpp> #include <beast/core/flat_buffer.hpp>
#include <beast/core/handler_alloc.hpp> #include <beast/core/handler_alloc.hpp>
@ -25,6 +26,8 @@
#include <beast/core/ostream.hpp> #include <beast/core/ostream.hpp>
#include <beast/core/static_buffer.hpp> #include <beast/core/static_buffer.hpp>
#include <beast/core/static_string.hpp> #include <beast/core/static_string.hpp>
#include <beast/core/string_param.hpp>
#include <beast/core/string_view.hpp>
#include <beast/core/type_traits.hpp> #include <beast/core/type_traits.hpp>
#endif #endif

View File

@ -0,0 +1,133 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_DETAIL_STATIC_OSTREAM_HPP
#define BEAST_DETAIL_STATIC_OSTREAM_HPP
#include <locale>
#include <ostream>
#include <streambuf>
namespace beast {
namespace detail {
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
class static_ostream_buffer
: public std::basic_streambuf<char>
{
using CharT = char;
using Traits = std::char_traits<CharT>;
using int_type = typename
std::basic_streambuf<CharT, Traits>::int_type;
using traits_type = typename
std::basic_streambuf<CharT, Traits>::traits_type;
char buf_[128];
std::string s_;
std::size_t len_ = 0;
public:
static_ostream_buffer(static_ostream_buffer&&) = delete;
static_ostream_buffer(static_ostream_buffer const&) = delete;
static_ostream_buffer()
{
this->setp(buf_, buf_ + sizeof(buf_) - 1);
}
~static_ostream_buffer() noexcept
{
}
string_view
str() const
{
if(! s_.empty())
return {s_.data(), len_};
return {buf_, len_};
}
int_type
overflow(int_type ch) override
{
if(! Traits::eq_int_type(ch, Traits::eof()))
{
Traits::assign(*this->pptr(), ch);
flush(1);
prepare();
return ch;
}
flush();
return traits_type::eof();
}
int
sync() override
{
flush();
prepare();
return 0;
}
private:
void
prepare()
{
static auto const growth_factor = 1.5;
if(len_ < sizeof(buf_) - 1)
{
this->setp(&buf_[len_],
&buf_[sizeof(buf_) - 2]);
return;
}
if(s_.empty())
{
s_.resize(static_cast<std::size_t>(
growth_factor * len_));
Traits::copy(&s_[0], buf_, len_);
}
else
{
s_.resize(static_cast<std::size_t>(
growth_factor * len_));
}
this->setp(&s_[len_], &s_[len_] +
s_.size() - len_ - 1);
}
void
flush(int extra = 0)
{
len_ += static_cast<std::size_t>(
this->pptr() - this->pbase() + extra);
}
};
class static_ostream : public std::basic_ostream<char>
{
static_ostream_buffer osb_;
public:
static_ostream()
: std::basic_ostream<char>(&this->osb_)
{
imbue(std::locale::classic());
}
string_view
str() const
{
return osb_.str();
}
};
} // detail
} // beast
#endif

View File

@ -0,0 +1,125 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_STRING_PARAM_HPP
#define BEAST_STRING_PARAM_HPP
#include <beast/config.hpp>
#include <beast/core/string_view.hpp>
#include <beast/core/detail/static_ostream.hpp>
#include <beast/core/detail/type_traits.hpp>
namespace beast {
/** A function parameter which efficiently converts to string.
This is used as a function parameter type to allow callers
notational convenience: objects other than strings may be
passed in contexts where a string is expected. The conversion
to string is made using `operator<<` to a non-dynamically
allocated static buffer if possible, else to a `std::string`
on overflow.
*/
class string_param
{
template<class T, class = void>
struct is_streamable : std::false_type{};
#if ! BEAST_DOXYGEN
template<class T>
struct is_streamable<T, detail::void_t<decltype(
std::declval<std::ostream&>() << std::declval<T const&>()
)>> : std::true_type {};
#endif
template<class T>
void
assign(T const& t, std::true_type)
{
sv_ = t;
}
template<class T>
void
assign(T const& t, std::false_type)
{
os_ << t;
os_.flush();
sv_ = os_.str();
}
detail::static_ostream os_;
string_view sv_;
public:
/// Copy constructor (disallowed)
string_param(string_param const&) = delete;
/// Copy assignment (disallowed)
string_param& operator=(string_param const&) = delete;
/** Constructor
This function constructs a string from the specified
parameter.
If @ref string_view is constructible from `T` then
the complexity is O(1), and no dynamic allocation
takes place.
Otherwise, the argument is converted to a string
as if by a call to `boost::lexical_cast<std::string>(t)`.
An attempt is made to store this string in a reasonably
sized buffer inside the class, to avoid dynamic allocation.
If the argument could not be converted given the space
of the class buffer, a final attempt is made to convert
the argument to a `std::string`. This attempt may cause
a memory allocation.
@param t The argument to convert to string.
@note This function participates in overload resolution
only if `T` is convertible to @ref string_view, or if
`operator<<(std::ostream&, T)` is defined.
*/
#if BEAST_DOXYGEN
template<class T>
#else
template<class T, class = typename std::enable_if<
std::is_convertible<T, string_view>::value ||
is_streamable<T>::value
>::type>
#endif
string_param(T const& t);
/// Conversion to @ref string_view for the converted argument.
string_view const
str() const
{
return sv_;
}
/// Conversion to @ref string_view operator
operator string_view const() const
{
return sv_;
}
};
#if ! BEAST_DOXYGEN
template<class T, class>
string_param::
string_param(T const& t)
{
assign(t, std::is_convertible<T, string_view>{});
}
#endif
} // beast
#endif

View File

@ -36,6 +36,7 @@ unit-test core-tests :
core/ostream.cpp core/ostream.cpp
core/static_buffer.cpp core/static_buffer.cpp
core/static_string.cpp core/static_string.cpp
core/string_param.cpp
core/string_view.cpp core/string_view.cpp
core/type_traits.cpp core/type_traits.cpp
core/base64.cpp core/base64.cpp

View File

@ -31,6 +31,7 @@ add_executable (core-tests
ostream.cpp ostream.cpp
static_buffer.cpp static_buffer.cpp
static_string.cpp static_string.cpp
string_param.cpp
string_view.cpp string_view.cpp
type_traits.cpp type_traits.cpp
base64.cpp base64.cpp

View File

@ -0,0 +1,44 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/string_param.hpp>
#include <beast/unit_test/suite.hpp>
#include <beast/core/detail/type_traits.hpp>
namespace beast {
class string_param_test : public unit_test::suite
{
public:
struct nop {};
static_assert(! std::is_constructible<string_param, nop>::value, "");
void
check(string_param const& v, string_view s)
{
BEAST_EXPECT(v.str() == s);
}
void
run() override
{
check(std::string("hello"), "hello");
check("xyz", "xyz");
check(1, "1");
check(12, "12");
check(123, "123");
check(1234, "1234");
check(12345, "12345");
}
};
BEAST_DEFINE_TESTSUITE(string_param,core,beast);
} // beast