2
0
mirror of https://github.com/boostorg/url.git synced 2026-02-21 15:32:13 +00:00

add string_token

This commit is contained in:
Vinnie Falco
2022-09-05 17:14:48 -07:00
parent 66b30150d4
commit 81bb6547f8
12 changed files with 492 additions and 4 deletions

View File

@@ -73,6 +73,16 @@
# define BOOST_URL_POS BOOST_CURRENT_LOCATION
#endif
#ifndef BOOST_URL_STRTOK_TPARAM
#define BOOST_URL_STRTOK_TPARAM(T) class T = string_token::return_string
#endif
#ifndef BOOST_URL_STRTOK_RETURN
#define BOOST_URL_STRTOK_RETURN(T) typename T::result_type
#endif
#ifndef BOOST_URL_STRTOK_ARG
#define BOOST_URL_STRTOK_ARG(T, name) T&& name = {}
#endif
#ifndef BOOST_URL_STACK_BYTES
#define BOOST_URL_STACK_BYTES 4096
#endif

View File

@@ -28,6 +28,7 @@
#include <boost/url/grammar/parse.hpp>
#include <boost/url/grammar/range_rule.hpp>
#include <boost/url/grammar/recycled.hpp>
#include <boost/url/grammar/string_token.hpp>
#include <boost/url/grammar/token_rule.hpp>
#include <boost/url/grammar/tuple_rule.hpp>
#include <boost/url/grammar/type_traits.hpp>

View File

@@ -38,6 +38,18 @@ namespace grammar {
the lifetime of the buffer extends until
it is no longer referenced by the range.
@note
The implementation may use temporary,
recycled storage for type-erasure. Objects
of type `range` are intended to be used
ephemerally. That is, for short durations
such as within a function scope. If it is
necessary to store the range for a long
period of time or with static storage
duration, it is necessary to copy the
contents to an object of a different type.
@tparam T The value type of the range
@see

View File

@@ -0,0 +1,348 @@
//
// Copyright (c) 2021 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)
//
// Official repository: https://github.com/CPPAlliance/url
//
#ifndef BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
#define BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/string_view.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/type_traits.hpp>
#include <memory>
#include <string>
namespace boost {
namespace urls {
namespace grammar {
namespace string_token {
/** Base class for string tokens, and algorithm parameters
This abstract interface provides a means
for an algorithm to generically obtain a
modifiable, contiguous character buffer
of prescribed size. As the author of an
algorithm simply declare an rvalue
reference as a parameter type.
<br>
Instances of this type are intended only
to be used once and then destroyed.
@par Example
The declared function will accept any
temporary instance of `arg` to be
used for writing:
@code
void algorithm( string_token::arg&& dest );
@endcode
To implement the interface for your type
or use-case, derive from the class and
implement the prepare function.
*/
struct arg
{
/** Return a modifiable character buffer
This function attempts to obtain a
character buffer with space for at
least `n` characters. Upon success,
a pointer to the beginning of the
buffer is returned. Ownership is not
transferred; the caller should not
attempt to free the storage. The
buffer shall remain valid until
`this` is destroyed.
@note
This function may only be called once.
After invoking the function, the only
valid operation is destruction.
*/
virtual char* prepare(std::size_t n) = 0;
// prevent misuse
arg() = default;
arg(arg&&) = default;
arg(arg const&) = delete;
arg& operator=(arg&&) = delete;
arg& operator=(arg const&) = delete;
};
//------------------------------------------------
/** Metafunction returning true if T is a StringToken
*/
#ifdef BOOST_URL_DOCS
template<class T>
using is_token = __see_below__;
#else
template<class T, class = void>
struct is_token : std::false_type {};
template<class T>
struct is_token<T, boost::void_t<
decltype(std::declval<T&>().prepare(
std::declval<std::size_t>())),
decltype(std::declval<T&>().result())
> > : std::integral_constant<bool,
std::is_convertible<decltype(
std::declval<T&>().result()),
typename T::result_type>::value &&
std::is_same<decltype(
std::declval<T&>().prepare(0)),
char*>::value &&
std::is_base_of<arg, T>::value &&
std::is_convertible<T const volatile*,
arg const volatile*>::value
>
{
};
#endif
//------------------------------------------------
/** A token for returning a plain string
*/
#ifdef BOOST_URL_DOCS
using return_string = __implementation_defined__;
#else
struct return_string
: arg
{
using result_type = std::string;
char*
prepare(std::size_t n) override
{
s_.resize(n);
return &s_[0];
}
result_type
result() noexcept
{
return std::move(s_);
}
private:
result_type s_;
};
#endif
//------------------------------------------------
/** A token for appending to a plain string
*/
#ifdef BOOST_URL_DOCS
template<
class Allocator =
std::allocator<char>>
__implementation_defined__
append_to(
std::basic_string<
char,
std::char_traits<char>,
Allocator>& s);
#else
template<class Alloc>
struct append_to_t
: arg
{
using string_type = std::basic_string<
char, std::char_traits<char>,
Alloc>;
using result_type = string_type&;
explicit
append_to_t(
string_type& s) noexcept
: s_(s)
{
}
char*
prepare(std::size_t n) override
{
std::size_t n0 = s_.size();
if(n > s_.max_size() - n0)
urls::detail::throw_bad_alloc();
s_.resize(n0 + n);
return &s_[n0];
}
result_type
result() noexcept
{
return s_;
}
private:
string_type& s_;
};
template<
class Alloc =
std::allocator<char>>
append_to_t<Alloc>
append_to(
std::basic_string<
char,
std::char_traits<char>,
Alloc>& s)
{
return append_to_t<Alloc>(s);
}
#endif
//------------------------------------------------
/** A token for assigning to a plain string
*/
#ifdef BOOST_URL_DOCS
template<
class Allocator =
std::allocator<char>>
__implementation_defined__
assign(
std::basic_string<
char,
std::char_traits<char>,
Allocator>& s);
#else
template<class Alloc>
struct assign_to_t
: arg
{
using string_type = std::basic_string<
char, std::char_traits<char>,
Alloc>;
using result_type = string_type&;
explicit
assign_to_t(
string_type& s) noexcept
: s_(s)
{
}
char*
prepare(std::size_t n) override
{
s_.resize(n);
return &s_[0];
}
result_type
result() noexcept
{
return s_;
}
private:
string_type& s_;
};
template<
class Alloc =
std::allocator<char>>
assign_to_t<Alloc>
assign_to(
std::basic_string<
char,
std::char_traits<char>,
Alloc>& s)
{
return assign_to_t<Alloc>(s);
}
#endif
//------------------------------------------------
/** A token for producing a durable string_view from a temporary string
*/
#ifdef BOOST_URL_DOCS
template<
class Allocator =
std::allocator<char>>
__implementation_defined__
preserve_size(
std::basic_string<
char,
std::char_traits<char>,
Allocator>& s);
#else
template<class Alloc>
struct preserve_size_t
: arg
{
using result_type = string_view;
using string_type = std::basic_string<
char, std::char_traits<char>,
Alloc>;
explicit
preserve_size_t(
string_type& s) noexcept
: s_(s)
{
}
char*
prepare(std::size_t n) override
{
n_ = n;
// preserve size() to
// avoid value-init
if(s_.size() < n)
s_.resize(n);
return &s_[0];
}
result_type
result() noexcept
{
return string_view(
s_.data(), n_);
}
private:
string_type& s_;
std::size_t n_ = 0;
};
template<
class Alloc =
std::allocator<char>>
preserve_size_t<Alloc>
preserve_size(
std::basic_string<
char,
std::char_traits<char>,
Alloc>& s)
{
return preserve_size_t<Alloc>(s);
}
#endif
} // string_token
} // grammar
namespace string_token = grammar::string_token;
} // urls
} // boost
#endif