update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -0,0 +1,88 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_ALL_CHARS_HPP
#define BOOST_URL_GRAMMAR_ALL_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of all characters
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > rv = parse( "JohnDoe", token_rule( all_chars ) );
@endcode
@par BNF
@code
ALL = %x00-FF
@endcode
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ all_chars;
#else
struct all_chars_t
{
constexpr
all_chars_t() noexcept = default;
constexpr
bool
operator()(char) const noexcept
{
return true;
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
/** A character set containing all characters.
@see
@ref all_chars_t
*/
constexpr all_chars_t all_chars{};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,93 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_ALNUM_CHARS_HPP
#define BOOST_URL_GRAMMAR_ALNUM_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of letters and digits
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > = parse( "Johnny42", token_rule( alnumchars ) );
@endcode
@par BNF
@code
ALNUM = ALPHA / DIGIT
ALPHA = %x41-5A / %x61-7A
; A-Z / a-z
DIGIT = %x30-39
; 0-9
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
>B.1. Core Rules (rfc5234)</a>
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ alnum_chars;
#else
struct alnum_chars_t
{
constexpr
bool
operator()(char c) const noexcept
{
return
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z');
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
constexpr alnum_chars_t alnum_chars{};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,95 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_ALPHA_CHARS_HPP
#define BOOST_URL_GRAMMAR_ALPHA_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of all letters
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > rv = parse( "JohnDoe", token_rule( alpha_chars ) );
@endcode
@par BNF
@code
ALPHA = %x41-5A / %x61-7A
; A-Z / a-z
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
>B.1. Core Rules (rfc5234)</a>
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ alpha_chars;
#else
struct alpha_chars_t
{
constexpr
alpha_chars_t() noexcept = default;
constexpr
bool
operator()(char c) const noexcept
{
return
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z');
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
/** A character set containing the alphabetical characters.
@see
@ref alpha_chars_t
*/
constexpr alpha_chars_t alpha_chars{};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,217 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_CHARSET_HPP
#define BOOST_URL_GRAMMAR_CHARSET_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
#include <boost/static_assert.hpp>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace boost {
namespace urls {
namespace grammar {
/** Alias for `std::true_type` if T satisfies <em>CharSet</em>.
This metafunction determines if the
type `T` meets these requirements of
<em>CharSet</em>:
@li An instance of `T` is invocable
with this equivalent function signature:
@code
bool T::operator()( char ) const noexcept;
@endcode
@par Example
Use with `enable_if` on the return value:
@code
template< class CharSet >
typename std::enable_if< is_charset<T>::value >::type
func( CharSet const& cs );
@endcode
@tparam T the type to check.
*/
#ifdef BOOST_URL_DOCS
template<class T>
using is_charset = __see_below__;
#else
template<class T, class = void>
struct is_charset : std::false_type {};
template<class T>
struct is_charset<T, void_t<
decltype(
std::declval<bool&>() =
std::declval<T const&>().operator()(
std::declval<char>())
) > > : std::true_type
{
};
#endif
//------------------------------------------------
/** Find the first character in the string that is in the set.
@par Exception Safety
Throws nothing.
@return A pointer to the found character,
otherwise the value `last`.
@param first A pointer to the first character
in the string to search.
@param last A pointer to one past the last
character in the string to search.
@param cs The character set to use.
@see
@ref find_if_not.
*/
template<class CharSet>
char const*
find_if(
char const* const first,
char const* const last,
CharSet const& cs) noexcept
{
// If you get a compile error here
// it means your type does not meet
// the requirements. Please check the
// documentation.
static_assert(
is_charset<CharSet>::value,
"CharSet requirements not met");
return detail::find_if(first, last, cs,
detail::has_find_if<CharSet>{});
}
/** Find the first character in the string that is not in CharSet
@par Exception Safety
Throws nothing.
@return A pointer to the found character,
otherwise the value `last`.
@param first A pointer to the first character
in the string to search.
@param last A pointer to one past the last
character in the string to search.
@param cs The character set to use.
@see
@ref find_if_not.
*/
template<class CharSet>
char const*
find_if_not(
char const* const first,
char const* const last,
CharSet const& cs) noexcept
{
// If you get a compile error here
// it means your type does not meet
// the requirements. Please check the
// documentation.
static_assert(
is_charset<CharSet>::value,
"CharSet requirements not met");
return detail::find_if_not(first, last, cs,
detail::has_find_if_not<CharSet>{});
}
//------------------------------------------------
#ifndef BOOST_URL_DOCS
namespace detail {
template<class CharSet>
struct charset_ref
{
CharSet const& cs_;
constexpr
bool
operator()(char ch) const noexcept
{
return cs_(ch);
}
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return grammar::find_if(
first, last, cs_);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return grammar::find_if_not(
first, last, cs_ );
}
};
} // detail
#endif
/** Return a reference to a character set
This function returns a character set which
references the specified object. This is
used to reduce the number of bytes of
storage (`sizeof`) required by a combinator
when it stores a copy of the object.
<br>
Ownership of the object is not transferred;
the caller is responsible for ensuring the
lifetime of the object is extended until it
is no longer referenced. For best results,
`ref` should only be used with compile-time
constants.
*/
template<class CharSet>
constexpr
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
typename std::enable_if<
is_charset<CharSet>::value &&
! std::is_same<CharSet,
detail::charset_ref<CharSet> >::value,
detail::charset_ref<CharSet> >::type
#endif
ref(CharSet const& cs) noexcept
{
return detail::charset_ref<
CharSet>{cs};
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,356 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_CI_STRING_HPP
#define BOOST_URL_GRAMMAR_CI_STRING_HPP
#include <boost/url/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/detail/ci_string.hpp>
#include <cstdlib>
namespace boost {
namespace urls {
namespace grammar {
// Algorithms for interacting with low-ASCII
// characters and strings, for implementing
// semantics in RFCs. These routines do not
// use std::locale.
//------------------------------------------------
/** Return c converted to lowercase
This function returns the character,
converting it to lowercase if it is
uppercase.
The function is defined only for
low-ASCII characters.
@par Example
@code
assert( to_lower( 'A' ) == 'a' );
@endcode
@par Exception Safety
Throws nothing.
@return The converted character
@param c The character to convert
@see
@ref to_upper.
*/
constexpr
char
to_lower(char c) noexcept
{
return detail::to_lower(c);
}
/** Return c converted to uppercase
This function returns the character,
converting it to uppercase if it is
lowercase.
The function is defined only for
low-ASCII characters.
@par Example
@code
assert( to_upper( 'a' ) == 'A' );
@endcode
@par Exception Safety
Throws nothing.
@return The converted character
@param c The character to convert
@see
@ref to_lower.
*/
constexpr
char
to_upper(char c) noexcept
{
return detail::to_upper(c);
}
//------------------------------------------------
/** Return the case-insensitive comparison of s0 and s1
This returns the lexicographical comparison
of two strings, ignoring case.
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
assert( ci_compare( "boost", "Boost" ) == 0 );
@endcode
@par Exception Safety
Throws nothing.
@return 0 if the strings are equal, -1 if
`s0` is less than `s1`, or 1 if `s0` is
greater than s1.
@param s0 The first string
@param s1 The second string
@see
@ref ci_is_equal,
@ref ci_is_less.
*/
BOOST_URL_DECL
int
ci_compare(
core::string_view s0,
core::string_view s1) noexcept;
/** Return the case-insensitive digest of a string
The hash function is non-cryptographic and
not hardened against algorithmic complexity
attacks.
Returned digests are suitable for usage in
unordered containers.
The function is defined only for strings
containing low-ASCII characters.
@return The digest
@param s The string
*/
BOOST_URL_DECL
std::size_t
ci_digest(
core::string_view s) noexcept;
//------------------------------------------------
/** Return true if s0 equals s1 using case-insensitive comparison
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
assert( ci_is_equal( "Boost", "boost" ) );
@endcode
@see
@ref ci_compare,
@ref ci_is_less.
*/
#ifdef BOOST_URL_DOCS
template<
class String0,
class String1>
bool
ci_is_equal(
String0 const& s0,
String1 const& s1);
#else
template<
class String0,
class String1>
auto
ci_is_equal(
String0 const& s0,
String1 const& s1) ->
typename std::enable_if<
! std::is_convertible<
String0, core::string_view>::value ||
! std::is_convertible<
String1, core::string_view>::value,
bool>::type
{
// this overload supports forward iterators and
// does not assume the existence core::string_view::size
if( detail::type_id<String0>() >
detail::type_id<String1>())
return detail::ci_is_equal(s1, s0);
return detail::ci_is_equal(s0, s1);
}
inline
bool
ci_is_equal(
core::string_view s0,
core::string_view s1) noexcept
{
// this overload is faster as it makes use of
// core::string_view::size
if(s0.size() != s1.size())
return false;
return detail::ci_is_equal(s0, s1);
}
#endif
/** Return true if s0 is less than s1 using case-insensitive comparison
The comparison algorithm implements a
case-insensitive total order on the set
of all strings; however, it is not a
lexicographical comparison.
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
assert( ! ci_is_less( "Boost", "boost" ) );
@endcode
@see
@ref ci_compare,
@ref ci_is_equal.
*/
inline
bool
ci_is_less(
core::string_view s0,
core::string_view s1) noexcept
{
if(s0.size() != s1.size())
return s0.size() < s1.size();
return detail::ci_is_less(s0, s1);
}
//------------------------------------------------
/** A case-insensitive hash function object for strings
The hash function is non-cryptographic and
not hardened against algorithmic complexity
attacks.
This is a suitable hash function for
unordered containers.
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
@endcode
@see
@ref ci_equal,
@ref ci_less.
*/
#ifdef BOOST_URL_DOCS
using ci_hash = __see_below__;
#else
struct ci_hash
{
using is_transparent = void;
std::size_t
operator()(
core::string_view s) const noexcept
{
return ci_digest(s);
}
};
#endif
/** A case-insensitive equals predicate for strings
The function object returns `true` when
two strings are equal, ignoring case.
This is a suitable equality predicate for
unordered containers.
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
boost::unordered_map< std::string, std::string, ci_hash, ci_equal > m1;
std::unordered_map < std::string, std::string, ci_hash, ci_equal > m2; // (since C++20)
@endcode
@see
@ref ci_hash,
@ref ci_less.
*/
#ifdef BOOST_URL_DOCS
using ci_equal = __see_below__;
#else
struct ci_equal
{
using is_transparent = void;
template<
class String0, class String1>
bool
operator()(
String0 s0,
String1 s1) const noexcept
{
return ci_is_equal(s0, s1);
}
};
#endif
/** A case-insensitive less predicate for strings
The comparison algorithm implements a
case-insensitive total order on the set
of all ASCII strings; however, it is
not a lexicographical comparison.
This is a suitable predicate for
ordered containers.
The function is defined only for strings
containing low-ASCII characters.
@par Example
@code
boost::container::map< std::string, std::string, ci_less > m1;
std::map< std::string, std::string, ci_less > m2; // (since C++14)
@endcode
@see
@ref ci_equal,
@ref ci_hash.
*/
#ifdef BOOST_URL_DOCS
using ci_less = __see_below__;
#else
struct ci_less
{
using is_transparent = void;
std::size_t
operator()(
core::string_view s0,
core::string_view s1) const noexcept
{
return ci_is_less(s0, s1);
}
};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,76 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DEC_OCTET_RULE_HPP
#define BOOST_URL_GRAMMAR_DEC_OCTET_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Match a decimal octet
A decimal octet is precise way of
saying a number from 0 to 255. These
are commonly used in IPv4 addresses.
@par Value Type
@code
using value_type = unsigned char;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< unsigned char > rv = parse( "255", dec_octet_rule );
@endcode
@par BNF
@code
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
>3.2.2. Host (rfc3986)</a>
@see
@ref parse.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ dec_octet_rule;
#else
struct dec_octet_rule_t
{
using value_type = unsigned char;
BOOST_URL_DECL
auto
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>;
};
constexpr dec_octet_rule_t dec_octet_rule{};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,188 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DELIM_RULE_HPP
#define BOOST_URL_GRAMMAR_DELIM_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/charset.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/type_traits.hpp>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
/** Match a character literal
This matches the specified character.
The value is a reference to the character
in the underlying buffer, expressed as a
`core::string_view`. The function @ref squelch
may be used to turn this into `void` instead.
If there is no more input, the error code
@ref error::need_more is returned.
@par Value Type
@code
using value_type = core::string_view;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< core::string_view > rv = parse( ".", delim_rule('.') );
@endcode
@par BNF
@code
char = %00-FF
@endcode
@param ch The character to match
@see
@ref parse,
@ref squelch.
*/
#ifdef BOOST_URL_DOCS
constexpr
__implementation_defined__
delim_rule( char ch ) noexcept;
#else
struct ch_delim_rule
{
using value_type = core::string_view;
constexpr
ch_delim_rule(char ch) noexcept
: ch_(ch)
{
}
BOOST_URL_DECL
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept;
private:
char ch_;
};
constexpr
ch_delim_rule
delim_rule( char ch ) noexcept
{
return ch_delim_rule(ch);
}
#endif
//------------------------------------------------
/** Match a single character from a character set
This matches exactly one character which
belongs to the specified character set.
The value is a reference to the character
in the underlying buffer, expressed as a
`core::string_view`. The function @ref squelch
may be used to turn this into `void` instead.
If there is no more input, the error code
@ref error::need_more is returned.
@par Value Type
@code
using value_type = core::string_view;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< core::string_view > rv = parse( "X", delim_rule( alpha_chars ) );
@endcode
@param cs The character set to use.
@see
@ref alpha_chars,
@ref parse,
@ref squelch.
*/
#ifdef BOOST_URL_DOCS
template<class CharSet>
constexpr
__implementation_defined__
delim_rule( CharSet const& cs ) noexcept;
#else
template<class CharSet>
struct cs_delim_rule
{
using value_type = core::string_view;
constexpr
cs_delim_rule(
CharSet const& cs) noexcept
: cs_(cs)
{
}
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept
{
if(it == end)
{
// end
BOOST_URL_RETURN_EC(
error::need_more);
}
if(! cs_(*it))
{
// wrong character
BOOST_URL_RETURN_EC(
error::mismatch);
}
return core::string_view{
it++, 1 };
}
private:
CharSet cs_;
};
template<class CharSet>
constexpr
typename std::enable_if<
! std::is_convertible<
CharSet, char>::value,
cs_delim_rule<CharSet>>::type
delim_rule(
CharSet const& cs) noexcept
{
// If you get a compile error here it
// means that your type does not meet
// the requirements for a CharSet.
// Please consult the documentation.
static_assert(
is_charset<CharSet>::value,
"CharSet requirements not met");
return cs_delim_rule<CharSet>(cs);
}
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,189 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DETAIL_CHARSET_HPP
#define BOOST_URL_GRAMMAR_DETAIL_CHARSET_HPP
#include <boost/core/bit.hpp>
#include <type_traits>
#ifdef BOOST_URL_USE_SSE2
# include <emmintrin.h>
# include <xmmintrin.h>
# ifdef _MSC_VER
# include <intrin.h>
# endif
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4127) // conditional expression is constant
#endif
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
template<class T, class = void>
struct has_find_if : std::false_type {};
template<class T>
struct has_find_if<T, void_t<
decltype(
std::declval<char const*&>() =
std::declval<T const&>().find_if(
std::declval<char const*>(),
std::declval<char const*>())
)>> : std::true_type
{
};
template<class T, class = void>
struct has_find_if_not : std::false_type {};
template<class T>
struct has_find_if_not<T, void_t<
decltype(
std::declval<char const*&>() =
std::declval<T const&>().find_if_not(
std::declval<char const*>(),
std::declval<char const*>())
)>> : std::true_type
{
};
template<class Pred>
char const*
find_if(
char const* first,
char const* const last,
Pred const& pred,
std::false_type) noexcept
{
while(first != last)
{
if(pred(*first))
break;
++first;
}
return first;
}
template<class Pred>
char const*
find_if(
char const* first,
char const* const last,
Pred const& pred,
std::true_type) noexcept
{
return pred.find_if(
first, last);
}
template<class Pred>
char const*
find_if_not(
char const* first,
char const* const last,
Pred const& pred,
std::false_type) noexcept
{
while(first != last)
{
if(! pred(*first))
break;
++first;
}
return first;
}
template<class Pred>
char const*
find_if_not(
char const* first,
char const* const last,
Pred const& pred,
std::true_type) noexcept
{
return pred.find_if_not(
first, last);
}
#ifdef BOOST_URL_USE_SSE2
// by Peter Dimov
template<class Pred>
char const*
find_if_pred(
Pred const& pred,
char const* first,
char const* last ) noexcept
{
while( last - first >= 16 )
{
unsigned char r[ 16 ] = {};
for( int i = 0; i < 16; ++i )
r[ i ] = pred( first[ i ] )? 0xFF: 0x00;
__m128i r2 = _mm_loadu_si128( (__m128i const*)r );
unsigned r3 = _mm_movemask_epi8( r2 );
if( r3 )
return first + boost::core::countr_zero( r3 );
first += 16;
}
while(
first != last &&
! pred(*first))
{
++first;
}
return first;
}
// by Peter Dimov
template<class Pred>
char const*
find_if_not_pred(
Pred const& pred,
char const* first,
char const* last ) noexcept
{
while( last - first >= 16 )
{
unsigned char r[ 16 ] = {};
for( int i = 0; i < 16; ++i )
r[ i ] = pred( first[ i ] )? 0x00: 0xFF;
__m128i r2 = _mm_loadu_si128( (__m128i const*)r );
unsigned r3 = _mm_movemask_epi8( r2 );
if( r3 )
return first + boost::core::countr_zero( r3 );
first += 16;
}
while(
first != last &&
pred(*first))
{
++first;
}
return first;
}
#endif
} // detail
} // grammar
} // urls
} // boost
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,179 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DETAIL_CI_STRING_HPP
#define BOOST_URL_GRAMMAR_DETAIL_CI_STRING_HPP
#include <boost/core/detail/string_view.hpp>
#include <boost/assert.hpp>
#include <cstdint>
#include <iterator>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
template<class T, class = void>
struct is_char_iter : std::false_type {};
template<class T>
struct is_char_iter<T, void_t<
decltype(std::declval<char&>() =
*std::declval<T const&>()),
decltype(std::declval<T&>() =
++std::declval<T&>()),
decltype(std::declval<bool&>() =
std::declval<T const&>() ==
std::declval<T const&>())
> > : std::integral_constant<bool,
std::is_copy_constructible<T>::value>
{
};
template<class T, class = void>
struct is_char_range : std::false_type {};
template<class T>
struct is_char_range<T, void_t<
decltype(std::declval<T const&>().begin()),
decltype(std::declval<T const&>().end())
> > : std::integral_constant<bool,
is_char_iter<decltype(
std::declval<T const&>(
).begin())>::value &&
is_char_iter<decltype(
std::declval<T const&>(
).end())>::value>
{
};
template<class T>
struct type_id_impl
{
static
constexpr
char cid = 0;
};
template<class T>
constexpr
char
type_id_impl<T>::cid;
template<class T>
constexpr
std::uintptr_t
type_id() noexcept
{
return std::uintptr_t(
&type_id_impl<T>::cid);
}
//------------------------------------------------
constexpr
char
to_lower(char c) noexcept
{
return
(c >= 'A' &&
c <= 'Z')
? c + 'a' - 'A'
: c;
}
constexpr
char
to_upper(char c) noexcept
{
return
(c >= 'a' &&
c <= 'z')
? c - ('a' - 'A')
: c;
}
//------------------------------------------------
template<class S0, class S1>
auto
ci_is_equal(
S0 const& s0,
S1 const& s1) ->
typename std::enable_if<
! std::is_convertible<
S0, core::string_view>::value ||
! std::is_convertible<
S1, core::string_view>::value,
bool>::type
{
/* If you get a compile error here, it
means that a range you passed does
not meet the requirements stated
in the documentation.
*/
static_assert(
is_char_range<S0>::value,
"Type requirements not met");
static_assert(
is_char_range<S1>::value,
"Type requirements not met");
// Arguments are sorted by type to
// reduce the number of function
// template instantiations. This
// works because:
//
// ci_is_equal(s0,s1) == ci_is_equal(s1,s0)
//
BOOST_ASSERT(
detail::type_id<S0>() <=
detail::type_id<S1>());
auto it0 = s0.begin();
auto it1 = s1.begin();
auto const end0 = s0.end();
auto const end1 = s1.end();
for(;;)
{
if(it0 == end0)
return it1 == end1;
if(it1 == end1)
return false;
if( to_lower(*it0) !=
to_lower(*it1))
return false;
++it0;
++it1;
}
}
//------------------------------------------------
BOOST_URL_DECL
bool
ci_is_equal(
core::string_view s0,
core::string_view s1) noexcept;
BOOST_URL_DECL
bool
ci_is_less(
core::string_view s0,
core::string_view s1) noexcept;
} // detail
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,102 @@
//
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DETAIL_RECYCLED_HPP
#define BOOST_URL_GRAMMAR_DETAIL_RECYCLED_HPP
#include <utility>
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
template<
std::size_t Size,
std::size_t Align>
struct aligned_storage_impl
{
void* addr() noexcept
{
return buf_;
}
void const* addr() const noexcept
{
return buf_;
}
private:
alignas(Align)
unsigned char buf_[Size];
};
constexpr
std::size_t
nearest_pow2(
std::size_t x,
std::size_t f = 0) noexcept
{
return
(f <= (std::size_t(-1)/2))
? ( x <= f
? f
: nearest_pow2(x, 2 * f))
: x;
}
//------------------------------------------------
BOOST_URL_DECL
void
recycled_add_impl(
std::size_t) noexcept;
BOOST_URL_DECL
void
recycled_remove_impl(
std::size_t) noexcept;
#ifdef BOOST_URL_REPORT
inline
void
recycled_add(
std::size_t n) noexcept
{
recycled_add_impl(n);
}
inline
void
recycled_remove(
std::size_t n) noexcept
{
recycled_remove_impl(n);
}
#else
inline void recycled_add(
std::size_t) noexcept
{
}
inline void recycled_remove(
std::size_t) noexcept
{
}
#endif
} // detail
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,212 @@
//
// Copyright (c) 2016-2019 Damian Jarek (damian dot jarek93 at gmail dot com)
// Copyright (c) 2022 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/boostorg/beast
//
#ifndef BOOST_URL_GRAMMAR_DETAIL_TUPLE_HPP
#define BOOST_URL_GRAMMAR_DETAIL_TUPLE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/copy_cv.hpp>
#include <cstdlib>
#include <utility>
#ifndef BOOST_URL_TUPLE_EBO
// VFALCO No idea what causes it or how to fix it
// https://devblogs.microsoft.com/cppblog/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
#ifdef BOOST_MSVC
#define BOOST_URL_TUPLE_EBO 0
#else
#define BOOST_URL_TUPLE_EBO 1
#endif
#endif
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
#if BOOST_URL_TUPLE_EBO
template<std::size_t I, class T>
struct tuple_element_impl
: empty_value<T>
{
constexpr
tuple_element_impl(T const& t)
: empty_value<T>(
empty_init, t)
{
}
constexpr
tuple_element_impl(T&& t)
: empty_value<T>(
empty_init,
std::move(t))
{
}
};
#else
template<std::size_t I, class T>
struct tuple_element_impl
{
T t_;
constexpr
tuple_element_impl(T const& t)
: t_(t)
{
}
constexpr
tuple_element_impl(T&& t)
: t_(std::move(t))
{
}
constexpr
T&
get() noexcept
{
return t_;
}
constexpr
T const&
get() const noexcept
{
return t_;
}
};
#endif
template<std::size_t I, class T>
struct tuple_element_impl<I, T&>
{
T& t;
constexpr
tuple_element_impl(T& t_)
: t(t_)
{
}
T&
get() const noexcept
{
return t;
}
};
template<class... Ts>
struct tuple_impl;
template<class... Ts, std::size_t... Is>
struct tuple_impl<
mp11::index_sequence<Is...>, Ts...>
: tuple_element_impl<Is, Ts>...
{
template<class... Us>
constexpr
explicit
tuple_impl(Us&&... us)
: tuple_element_impl<Is, Ts>(
std::forward<Us>(us))...
{
}
};
template<class... Ts>
struct tuple
: tuple_impl<
mp11::index_sequence_for<Ts...>, Ts...>
{
template<class... Us,
typename std::enable_if<
mp11::mp_bool<
mp11::mp_all<std::is_constructible<
Ts, Us>...>::value &&
! mp11::mp_all<std::is_convertible<
Us, Ts>...>::value>::value,
int>::type = 0
>
constexpr
explicit
tuple(Us&&... us) noexcept
: tuple_impl<mp11::index_sequence_for<
Ts...>, Ts...>{std::forward<Us>(us)...}
{
}
template<class... Us,
typename std::enable_if<
mp11::mp_all<std::is_convertible<
Us, Ts>...>::value,
int>::type = 0
>
constexpr
tuple(Us&&... us) noexcept
: tuple_impl<mp11::index_sequence_for<
Ts...>, Ts...>{std::forward<Us>(us)...}
{
}
};
//------------------------------------------------
template<std::size_t I, class T>
constexpr
T&
get(tuple_element_impl<I, T>& te)
{
return te.get();
}
template<std::size_t I, class T>
constexpr
T const&
get(tuple_element_impl<I, T> const& te)
{
return te.get();
}
template<std::size_t I, class T>
constexpr
T&&
get(tuple_element_impl<I, T>&& te)
{
return std::move(te.get());
}
template<std::size_t I, class T>
constexpr
T&
get(tuple_element_impl<I, T&>&& te)
{
return te.get();
}
template<std::size_t I, class T>
using tuple_element =
typename boost::copy_cv<
mp11::mp_at_c<typename
remove_cv<T>::type,
I>, T>::type;
} // detail
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,85 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DIGIT_CHARS_HPP
#define BOOST_URL_GRAMMAR_DIGIT_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of decimal digits
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > rv = parse( "2022", token_rule( digit_chars ) );
@endcode
@par BNF
@code
DIGIT = %x30-39
; 0-9
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
>B.1. Core Rules (rfc5234)</a>
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ digit_chars;
#else
struct digit_chars_t
{
constexpr
bool
operator()(char c) const noexcept
{
return c >= '0' && c <= '9';
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
constexpr digit_chars_t digit_chars{};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,130 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_ERROR_HPP
#define BOOST_URL_GRAMMAR_ERROR_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Error codes returned when using rules
@see
@ref condition,
@ref parse.
*/
enum class error
{
// VFALCO 3 space indent or
// else Doxygen malfunctions
//
// (informational)
//
/**
* More input is needed to match the rule
*
* A rule reached the end of the input,
* resulting in a partial match. The error
* is recoverable; the caller may obtain
* more input if possible and attempt to
* parse the character buffer again.
* Custom rules should only return this
* error if it is completely unambiguous
* that the rule cannot be matched without
* more input.
*/
need_more = 1,
/**
* The rule did not match the input.
*
* This error is returned when a rule fails
* to match the input. The error is recoverable;
* the caller may rewind the input pointer and
* attempt to parse again using a different rule.
*/
mismatch,
/**
* A rule reached the end of a range
*
* This indicates that the input was consumed
* when parsing a @ref range. The @ref range_rule
* avoids rewinding the input buffer when
* this error is returned. Thus the consumed
* characters are be considered part of the
* range without contributing additional
* elements.
*/
end_of_range,
/**
* Leftover input remaining after match.
*/
leftover,
//--------------------------------------------
//
// condition::fatal
//
//--------------------------------------------
/**
* A rule encountered unrecoverable invalid input.
*
* This error is returned when input is matching
* but one of the requirements is violated. For
* example if a percent escape is found, but
* one or both characters that follow are not
* valid hexadecimal digits. This is usually an
* unrecoverable error.
*/
invalid,
/** An integer overflowed during parsing.
*/
out_of_range,
/**
* An unspecified syntax error was found.
*/
syntax
};
//------------------------------------------------
/** Error conditions for errors received from rules
@see
@ref error,
@ref parse.
*/
enum class condition
{
/**
* A fatal error in syntax was encountered.
This indicates that parsing cannot continue.
*/
fatal = 1
};
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/error.hpp>
#endif

View File

@@ -0,0 +1,158 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_HEXDIG_CHARS_HPP
#define BOOST_URL_GRAMMAR_HEXDIG_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of hexadecimal digits
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > rv = parse( "8086FC19", token_rule( hexdig_chars ) );
@endcode
@par BNF
@code
HEXDIG = DIGIT
/ "A" / "B" / "C" / "D" / "E" / "F"
/ "a" / "b" / "c" / "d" / "e" / "f"
@endcode
@note The RFCs are inconsistent on the case
sensitivity of hexadecimal digits. Existing
uses suggest case-insensitivity is a de-facto
standard.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
>B.1. Core Rules (rfc5234)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-1.2"
>1.2. Syntax Notation (rfc7230)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc5952#section-2.3"
>2.3. Uppercase or Lowercase (rfc5952)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc5952#section-4.3"
>4.3. Lowercase (rfc5952)</a>
@see
@ref find_if,
@ref find_if_not,
@ref hexdig_value,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ hexdig_chars;
#else
struct hexdig_chars_t
{
/** Return true if c is in the character set.
*/
constexpr
bool
operator()(char c) const noexcept
{
return
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f');
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
constexpr hexdig_chars_t hexdig_chars{};
#endif
// VFALCO We can declare
// these later if needed
//
//struct hexdig_upper_chars;
//struct hexdig_lower_chars;
/** Return the decimal value of a hex character
This function returns the decimal
value of a hexadecimal character,
or -1 if the argument is not a
valid hexadecimal digit.
@par BNF
@code
HEXDIG = DIGIT
/ "A" / "B" / "C" / "D" / "E" / "F"
/ "a" / "b" / "c" / "d" / "e" / "f"
@endcode
@param ch The character to check
@return The decimal value or -1
*/
inline
signed char
hexdig_value(char ch) noexcept
{
// Idea for switch statement to
// minimize emitted assembly from
// Glen Fernandes
signed char res;
switch(ch)
{
default: res = -1; break;
case '0': res = 0; break;
case '1': res = 1; break;
case '2': res = 2; break;
case '3': res = 3; break;
case '4': res = 4; break;
case '5': res = 5; break;
case '6': res = 6; break;
case '7': res = 7; break;
case '8': res = 8; break;
case '9': res = 9; break;
case 'a': case 'A': res = 10; break;
case 'b': case 'B': res = 11; break;
case 'c': case 'C': res = 12; break;
case 'd': case 'D': res = 13; break;
case 'e': case 'E': res = 14; break;
case 'f': case 'F': res = 15; break;
}
return res;
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,123 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_ERROR_HPP
#define BOOST_URL_GRAMMAR_IMPL_ERROR_HPP
#include <type_traits>
namespace boost {
namespace system {
template<>
struct is_error_code_enum<
::boost::urls::grammar::error>
{
static bool const value = true;
};
template<>
struct is_error_condition_enum<
::boost::urls::grammar::condition>
{
static bool const value = true;
};
} // system
} // boost
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
struct BOOST_SYMBOL_VISIBLE
error_cat_type
: system::error_category
{
BOOST_URL_DECL
const char* name(
) const noexcept override;
BOOST_URL_DECL
std::string message(
int) const override;
BOOST_URL_DECL
char const* message(
int, char*, std::size_t
) const noexcept override;
BOOST_URL_DECL
system::error_condition
default_error_condition(
int code) const noexcept override;
BOOST_SYSTEM_CONSTEXPR error_cat_type() noexcept
: error_category(0x0536e50a30f9e9f2)
{
}
};
struct BOOST_SYMBOL_VISIBLE
condition_cat_type
: system::error_category
{
BOOST_URL_DECL
const char* name(
) const noexcept override;
BOOST_URL_DECL
std::string message(
int) const override;
BOOST_URL_DECL
char const* message(
int, char*, std::size_t
) const noexcept override;
BOOST_SYSTEM_CONSTEXPR condition_cat_type()
: error_category(0x0536e50a30f9e9f2)
{
}
};
BOOST_URL_DECL extern
error_cat_type error_cat;
BOOST_URL_DECL extern
condition_cat_type condition_cat;
} // detail
inline
system::error_code
make_error_code(
error ev) noexcept
{
return system::error_code{
static_cast<std::underlying_type<
error>::type>(ev),
detail::error_cat};
}
inline
system::error_condition
make_error_condition(
condition c) noexcept
{
return system::error_condition{
static_cast<std::underlying_type<
condition>::type>(c),
detail::condition_cat};
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,55 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_NOT_EMPTY_RULE_HPP
#define BOOST_URL_GRAMMAR_IMPL_NOT_EMPTY_RULE_HPP
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/parse.hpp>
namespace boost {
namespace urls {
namespace grammar {
template<class R>
auto
not_empty_rule_t<R>::
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
{
if(it == end)
{
// empty
BOOST_URL_RETURN_EC(
error::mismatch);
}
auto const it0 = it;
auto rv = r_.parse(it, end);
if( !rv )
{
// error
return rv;
}
if(it == it0)
{
// empty
BOOST_URL_RETURN_EC(
error::mismatch);
}
// value
return rv;
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,42 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_OPTIONAL_RULE_HPP
#define BOOST_URL_GRAMMAR_IMPL_OPTIONAL_RULE_HPP
#include <boost/url/grammar/error.hpp>
namespace boost {
namespace urls {
namespace grammar {
template<class R>
auto
optional_rule_t<R>::
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
{
if(it == end)
return boost::none;
auto const it0 = it;
auto rv =
this->get().parse(it, end);
if(rv)
return value_type(*rv);
it = it0;
return boost::none;
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,67 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_PARSE_HPP
#define BOOST_URL_GRAMMAR_IMPL_PARSE_HPP
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/type_traits.hpp>
namespace boost {
namespace urls {
namespace grammar {
template<class R>
BOOST_URL_NO_INLINE
auto
parse(
char const*& it,
char const* end,
R const& r) ->
system::result<typename R::value_type>
{
// If this goes off, it means the rule
// passed in did not meet the requirements.
// Please check the documentation.
static_assert(
is_rule<R>::value,
"Rule requirements not met");
return r.parse(it, end);
}
template<class R>
BOOST_URL_NO_INLINE
auto
parse(
core::string_view s,
R const& r) ->
system::result<typename R::value_type>
{
// If this goes off, it means the rule
// passed in did not meet the requirements.
// Please check the documentation.
static_assert(
is_rule<R>::value,
"Rule requirements not met");
auto it = s.data();
auto const end = it + s.size();
auto rv = r.parse(it, end);
if( rv &&
it != end)
return error::leftover;
return rv;
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,742 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_RANGE_HPP
#define BOOST_URL_GRAMMAR_IMPL_RANGE_HPP
#include <boost/url/detail/except.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/recycled.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <exception>
#include <iterator>
#include <new>
#include <stddef.h> // ::max_align_t
namespace boost {
namespace urls {
namespace grammar {
// VFALCO This could be reused for
// other things that need to type-erase
//------------------------------------------------
//
// any_rule
//
//------------------------------------------------
// base class for the type-erased rule pair
template<class T>
struct range<T>::
any_rule
{
virtual
~any_rule() = default;
virtual
void
move(void* dest) noexcept
{
::new(dest) any_rule(
std::move(*this));
}
virtual
void
copy(void* dest) const noexcept
{
::new(dest) any_rule(*this);
}
virtual
system::result<T>
first(
char const*&,
char const*) const noexcept
{
return system::error_code{};
}
virtual
system::result<T>
next(
char const*&,
char const*) const noexcept
{
return system::error_code{};
}
};
//------------------------------------------------
// small
template<class T>
template<class R, bool Small>
struct range<T>::impl1
: any_rule
, private empty_value<R>
{
explicit
impl1(R const& next) noexcept
: empty_value<R>(
empty_init,
next)
{
}
private:
impl1(impl1&&) noexcept = default;
impl1(impl1 const&) noexcept = default;
void
move(void* dest
) noexcept override
{
::new(dest) impl1(
std::move(*this));
}
void
copy(void* dest
) const noexcept override
{
::new(dest) impl1(*this);
}
system::result<T>
first(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, this->get());
}
system::result<T>
next(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, this->get());
}
};
//------------------------------------------------
// big
template<class T>
template<class R>
struct range<T>::impl1<R, false>
: any_rule
{
explicit
impl1(R const& next) noexcept
{
::new(p_->addr()) impl{next};
}
private:
struct impl
{
R r;
};
recycled_ptr<
aligned_storage<impl>> p_;
impl1(impl1&&) noexcept = default;
impl1(impl1 const&) noexcept = default;
impl const&
get() const noexcept
{
return *reinterpret_cast<
impl const*>(p_->addr());
}
~impl1()
{
if(p_)
get().~impl();
}
void
move(void* dest
) noexcept override
{
::new(dest) impl1(
std::move(*this));
}
void
copy(void* dest
) const noexcept override
{
::new(dest) impl1(*this);
}
system::result<T>
first(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, this->get().r);
}
system::result<T>
next(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, this->get().r);
}
};
//------------------------------------------------
// small
template<class T>
template<
class R0, class R1, bool Small>
struct range<T>::impl2
: any_rule
, private empty_value<R0, 0>
, private empty_value<R1, 1>
{
impl2(
R0 const& first,
R1 const& next) noexcept
: empty_value<R0,0>(
empty_init, first)
, empty_value<R1,1>(
empty_init, next)
{
}
private:
impl2(impl2&&) noexcept = default;
impl2(impl2 const&) noexcept = default;
void
move(void* dest
) noexcept override
{
::new(dest) impl2(
std::move(*this));
}
void
copy(void* dest
) const noexcept override
{
::new(dest) impl2(*this);
}
system::result<T>
first(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(it, end,
empty_value<
R0,0>::get());
}
system::result<T>
next(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(it, end,
empty_value<
R1,1>::get());
}
};
//------------------------------------------------
// big
template<class T>
template<
class R0, class R1>
struct range<T>::impl2<R0, R1, false>
: any_rule
{
impl2(
R0 const& first,
R1 const& next) noexcept
{
::new(p_->addr()) impl{
first, next};
}
private:
struct impl
{
R0 first;
R1 next;
};
recycled_ptr<
aligned_storage<impl>> p_;
impl2(impl2&&) noexcept = default;
impl2(impl2 const&) noexcept = default;
impl const&
get() const noexcept
{
return *reinterpret_cast<
impl const*>(p_->addr());
}
~impl2()
{
if(p_)
get().~impl();
}
void
move(void* dest
) noexcept override
{
::new(dest) impl2(
std::move(*this));
}
void
copy(void* dest
) const noexcept override
{
::new(dest) impl2(*this);
}
system::result<T>
first(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, get().first);
}
system::result<T>
next(
char const*& it,
char const* end)
const noexcept override
{
return grammar::parse(
it, end, get().next);
}
};
//------------------------------------------------
//
// iterator
//
//------------------------------------------------
template<class T>
class range<T>::
iterator
{
public:
using value_type = T;
using reference = T const&;
using pointer = void const*;
using difference_type =
std::ptrdiff_t;
using iterator_category =
std::forward_iterator_tag;
iterator() = default;
iterator(
iterator const&) = default;
iterator& operator=(
iterator const&) = default;
reference
operator*() const noexcept
{
return *rv_;
}
bool
operator==(
iterator const& other) const noexcept
{
// can't compare iterators
// from different containers!
BOOST_ASSERT(r_ == other.r_);
return p_ == other.p_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return !(*this == other);
}
iterator&
operator++() noexcept
{
BOOST_ASSERT(
p_ != nullptr);
auto const end =
r_->s_.data() +
r_->s_.size();
rv_ = r_->get().next(p_, end);
if( !rv_ )
p_ = nullptr;
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
private:
friend class range<T>;
range<T> const* r_ = nullptr;
char const* p_ = nullptr;
system::result<T> rv_;
iterator(
range<T> const& r) noexcept
: r_(&r)
, p_(r.s_.data())
{
auto const end =
r_->s_.data() +
r_->s_.size();
rv_ = r_->get().first(p_, end);
if( !rv_ )
p_ = nullptr;
}
constexpr
iterator(
range<T> const& r,
int) noexcept
: r_(&r)
, p_(nullptr)
{
}
};
//------------------------------------------------
template<class T>
template<class R>
range<T>::
range(
core::string_view s,
std::size_t n,
R const& next)
: s_(s)
, n_(n)
{
BOOST_STATIC_ASSERT(
sizeof(impl1<R, false>) <=
BufferSize);
::new(&get()) impl1<R,
sizeof(impl1<R, true>) <=
BufferSize>(next);
}
//------------------------------------------------
template<class T>
template<
class R0, class R1>
range<T>::
range(
core::string_view s,
std::size_t n,
R0 const& first,
R1 const& next)
: s_(s)
, n_(n)
{
BOOST_STATIC_ASSERT(
sizeof(impl2<R0, R1, false>) <=
BufferSize);
::new(&get()) impl2<R0, R1,
sizeof(impl2<R0, R1, true>
) <= BufferSize>(
first, next);
}
//------------------------------------------------
template<class T>
range<T>::
~range()
{
get().~any_rule();
}
template<class T>
range<T>::
range() noexcept
{
::new(&get()) any_rule{};
char const* it = nullptr;
get().first(it, nullptr);
get().next(it, nullptr);
}
template<class T>
range<T>::
range(
range&& other) noexcept
: s_(other.s_)
, n_(other.n_)
{
other.s_ = {};
other.n_ = {};
other.get().move(&get());
other.get().~any_rule();
::new(&other.get()) any_rule{};
}
template<class T>
range<T>::
range(
range const& other) noexcept
: s_(other.s_)
, n_(other.n_)
{
other.get().copy(&get());
}
template<class T>
auto
range<T>::
operator=(
range&& other) noexcept ->
range&
{
s_ = other.s_;
n_ = other.n_;
other.s_ = {};
other.n_ = 0;
// VFALCO we rely on nothrow move
// construction here, but if necessary we
// could move to a local buffer first.
get().~any_rule();
other.get().move(&get());
other.get().~any_rule();
::new(&other.get()) any_rule{};
return *this;
}
template<class T>
auto
range<T>::
operator=(
range const& other) noexcept ->
range&
{
s_ = other.s_;
n_ = other.n_;
// VFALCO we rely on nothrow copy
// construction here, but if necessary we
// could construct to a local buffer first.
get().~any_rule();
other.get().copy(&get());
return *this;
}
template<class T>
auto
range<T>::
begin() const noexcept ->
iterator
{
return { *this };
}
template<class T>
auto
range<T>::
end() const noexcept ->
iterator
{
return { *this, 0 };
}
//------------------------------------------------
template<class R>
auto
range_rule_t<R>::
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
{
using T = typename R::value_type;
std::size_t n = 0;
auto const it0 = it;
auto it1 = it;
auto rv = (grammar::parse)(
it, end, next_);
if( !rv )
{
if(rv.error() != error::end_of_range)
{
// rewind unless error::end_of_range
it = it1;
}
if(n < N_)
{
// too few
BOOST_URL_RETURN_EC(
error::mismatch);
}
// good
return range<T>(
core::string_view(it0, it - it0),
n, next_);
}
for(;;)
{
++n;
it1 = it;
rv = (grammar::parse)(
it, end, next_);
if( !rv )
{
if(rv.error() != error::end_of_range)
{
// rewind unless error::end_of_range
it = it1;
}
break;
}
if(n >= M_)
{
// too many
BOOST_URL_RETURN_EC(
error::mismatch);
}
}
if(n < N_)
{
// too few
BOOST_URL_RETURN_EC(
error::mismatch);
}
// good
return range<T>(
core::string_view(it0, it - it0),
n, next_);
}
//------------------------------------------------
template<class R0, class R1>
auto
range_rule_t<R0, R1>::
parse(
char const*& it,
char const* end) const ->
system::result<range<typename
R0::value_type>>
{
using T = typename R0::value_type;
std::size_t n = 0;
auto const it0 = it;
auto it1 = it;
auto rv = (grammar::parse)(
it, end, first_);
if( !rv )
{
if(rv.error() != error::end_of_range)
{
// rewind unless error::end_of_range
it = it1;
}
if(n < N_)
{
// too few
BOOST_URL_RETURN_EC(
error::mismatch);
}
// good
return range<T>(
core::string_view(it0, it - it0),
n, first_, next_);
}
for(;;)
{
++n;
it1 = it;
rv = (grammar::parse)(
it, end, next_);
if( !rv )
{
if(rv.error() != error::end_of_range)
{
// rewind unless error::end_of_range
it = it1;
}
break;
}
if(n >= M_)
{
// too many
BOOST_URL_RETURN_EC(
error::mismatch);
}
}
if(n < N_)
{
// too few
BOOST_URL_RETURN_EC(
error::mismatch);
}
// good
return range<T>(
core::string_view(it0, it - it0),
n, first_, next_);
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,221 @@
//
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
#define BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
#include <boost/assert.hpp>
namespace boost {
namespace urls {
namespace grammar {
//------------------------------------------------
template<class T>
recycled<T>::
~recycled()
{
std::size_t n = 0;
// VFALCO we should probably deallocate
// in reverse order of allocation but
// that requires a doubly-linked list.
auto it = head_;
while(it)
{
++n;
auto next = it->next;
BOOST_ASSERT(
it->refs == 0);
delete it;
it = next;
}
detail::recycled_remove(
sizeof(U) * n);
}
template<class T>
auto
recycled<T>::
acquire() ->
U*
{
U* p;
{
#if !defined(BOOST_URL_DISABLE_THREADS)
std::lock_guard<
std::mutex> lock(m_);
#endif
p = head_;
if(p)
{
// reuse
head_ = head_->next;
detail::recycled_remove(
sizeof(U));
++p->refs;
}
else
{
p = new U;
}
}
BOOST_ASSERT(p->refs == 1);
return p;
}
template<class T>
void
recycled<T>::
release(U* u) noexcept
{
if(--u->refs != 0)
return;
{
#if !defined(BOOST_URL_DISABLE_THREADS)
std::lock_guard<
std::mutex> lock(m_);
#endif
u->next = head_;
head_ = u;
}
detail::recycled_add(
sizeof(U));
}
//------------------------------------------------
template<class T>
recycled_ptr<T>::
~recycled_ptr()
{
if(p_)
bin_->release(p_);
}
template<class T>
recycled_ptr<T>::
recycled_ptr(
recycled<T>& bin)
: bin_(&bin)
, p_(bin.acquire())
{
}
template<class T>
recycled_ptr<T>::
recycled_ptr(
recycled<T>& bin,
std::nullptr_t) noexcept
: bin_(&bin)
{
}
template<class T>
recycled_ptr<T>::
recycled_ptr()
: recycled_ptr(nullptr)
{
p_ = bin_->acquire();
}
template<class T>
recycled_ptr<T>::
recycled_ptr(
std::nullptr_t) noexcept
: recycled_ptr([]() -> B&
{
// VFALCO need guaranteed constexpr-init
static B r;
return r;
}(), nullptr)
{
}
template<class T>
recycled_ptr<T>::
recycled_ptr(
recycled_ptr const& other) noexcept
: bin_(other.bin_)
, p_(other.p_)
{
if(p_)
++p_->refs;
}
template<class T>
recycled_ptr<T>::
recycled_ptr(
recycled_ptr&& other) noexcept
: bin_(other.bin_)
, p_(other.p_)
{
other.p_ = nullptr;
}
template<class T>
auto
recycled_ptr<T>::
operator=(
recycled_ptr&& other) noexcept ->
recycled_ptr&
{
BOOST_ASSERT(
bin_ == other.bin_);
if(p_)
bin_->release(p_);
p_ = other.p_;
other.p_ = nullptr;
return *this;
}
template<class T>
auto
recycled_ptr<T>::
operator=(
recycled_ptr const& other) noexcept ->
recycled_ptr&
{
BOOST_ASSERT(
bin_ == other.bin_);
if(p_)
bin_->release(p_);
p_ = other.p_;
if(p_)
++p_->refs;
return *this;
}
template<class T>
T&
recycled_ptr<T>::
acquire()
{
if(! p_)
p_ = bin_->acquire();
return p_->t;
}
template<class T>
void
recycled_ptr<T>::
release() noexcept
{
if(p_)
{
bin_->release(p_);
p_ = nullptr;
}
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,45 @@
//
// Copyright (c) 2016-2019 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/boostorg/http_proto
//
#ifndef BOOST_URL_IMPL_GRAMMAR_TOKEN_RULE_HPP
#define BOOST_URL_IMPL_GRAMMAR_TOKEN_RULE_HPP
#include <boost/url/grammar/error.hpp>
namespace boost {
namespace urls {
namespace grammar {
template<class CharSet>
auto
token_rule_t<CharSet>::
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>
{
auto const it0 = it;
if(it == end)
{
BOOST_URL_RETURN_EC(
error::need_more);
}
it = (find_if_not)(it, end, cs_);
if(it != it0)
return core::string_view(it0, it - it0);
BOOST_URL_RETURN_EC(
error::mismatch);
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,285 @@
//
// Copyright (c) 2022 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_TUPLE_RULE_HPP
#define BOOST_URL_GRAMMAR_IMPL_TUPLE_RULE_HPP
#include <boost/url/grammar/parse.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/tuple.hpp>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
// returns a tuple
template<
bool IsList,
class R0, class... Rn>
struct parse_sequence
{
using R = detail::tuple<R0, Rn...>;
using L = mp11::mp_list<
typename R0::value_type,
typename Rn::value_type...>;
using V = mp11::mp_remove<
std::tuple<
system::result<typename R0::value_type>,
system::result<typename Rn::value_type>...>,
system::result<void>>;
template<std::size_t I>
using is_void = std::is_same<
mp11::mp_at_c<L, I>, void>;
system::error_code ec;
R const& rn;
V vn;
explicit
parse_sequence(
R const& rn_) noexcept
: rn(rn_)
, vn(mp11::mp_fill<
V, system::error_code>{})
{
}
void
apply(
char const*&,
char const*,
...) const noexcept
{
}
// for system::result<void>
template<
std::size_t Ir,
std::size_t Iv>
void
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const&,
mp11::mp_size_t<Iv> const&,
mp11::mp_true const&)
{
system::result<void> rv =
grammar::parse(
it, end, get<Ir>(rn));
if( !rv )
{
ec = rv.error();
return;
}
apply(it, end,
mp11::mp_size_t<Ir+1>{},
mp11::mp_size_t<Iv>{});
}
template<
std::size_t Ir,
std::size_t Iv>
void
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const&,
mp11::mp_size_t<Iv> const&,
mp11::mp_false const&)
{
auto& rv = get<Iv>(vn);
rv = grammar::parse(
it, end, get<Ir>(rn));
if( !rv )
{
ec = rv.error();
return;
}
apply(it, end,
mp11::mp_size_t<Ir+1>{},
mp11::mp_size_t<Iv+1>{});
}
template<
std::size_t Ir = 0,
std::size_t Iv = 0>
typename std::enable_if<
Ir < 1 + sizeof...(Rn)>::type
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const& ir = {},
mp11::mp_size_t<Iv> const& iv = {}
) noexcept
{
apply(it, end, ir, iv, is_void<Ir>{});
}
struct deref
{
template<class R>
auto
operator()(R const& r) const ->
decltype(*r)
{
return *r;
}
};
auto
make_result() noexcept ->
system::result<typename tuple_rule_t<
R0, Rn...>::value_type>
{
if(ec.failed())
return ec;
return mp11::tuple_transform(
deref{}, vn);
}
};
// returns a value_type
template<class R0, class... Rn>
struct parse_sequence<false, R0, Rn...>
{
using R = detail::tuple<R0, Rn...>;
using L = mp11::mp_list<
typename R0::value_type,
typename Rn::value_type...>;
using V = mp11::mp_first<
mp11::mp_remove<
mp11::mp_list<
system::result<typename R0::value_type>,
system::result<typename Rn::value_type>...>,
system::result<void>>>;
template<std::size_t I>
using is_void = std::is_same<
mp11::mp_at_c<L, I>, void>;
R const& rn;
V v;
explicit
parse_sequence(
R const& rn_) noexcept
: rn(rn_)
, v(system::error_code{})
{
}
void
apply(
char const*&,
char const*,
...) const noexcept
{
}
// for system::result<void>
template<
std::size_t Ir,
std::size_t Iv>
BOOST_URL_NO_INLINE
void
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const&,
mp11::mp_size_t<Iv> const&,
mp11::mp_true const&)
{
system::result<void> rv =
grammar::parse(
it, end, get<Ir>(rn));
if( !rv )
{
v = rv.error();
return;
}
apply(it, end,
mp11::mp_size_t<Ir+1>{},
mp11::mp_size_t<Iv>{});
}
template<
std::size_t Ir,
std::size_t Iv>
void
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const&,
mp11::mp_size_t<Iv> const&,
mp11::mp_false const&)
{
v = grammar::parse(
it, end, get<Ir>(rn));
if( !v )
return;
apply(it, end,
mp11::mp_size_t<Ir+1>{},
mp11::mp_size_t<Iv+1>{});
}
template<
std::size_t Ir = 0,
std::size_t Iv = 0>
typename std::enable_if<
Ir < 1 + sizeof...(Rn)>::type
apply(
char const*& it,
char const* end,
mp11::mp_size_t<Ir> const& ir = {},
mp11::mp_size_t<Iv> const& iv = {}
) noexcept
{
apply(it, end, ir, iv, is_void<Ir>{});
}
V
make_result() noexcept
{
return v;
}
};
} // detail
template<
class R0,
class... Rn>
auto
tuple_rule_t<R0, Rn...>::
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
{
detail::parse_sequence<
IsList, R0, Rn...> t(this->get());
t.apply(it, end);
return t.make_result();
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,109 @@
//
// Copyright (c) 2022 Alan de Freitas (alandefreitas 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
#define BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/digit_chars.hpp>
#include <algorithm> // VFALCO grr..
namespace boost {
namespace urls {
namespace grammar {
template<class U>
auto
unsigned_rule<U>::
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>
{
if(it == end)
{
// end
BOOST_URL_RETURN_EC(
error::mismatch);
}
if(*it == '0')
{
++it;
if( it == end ||
! digit_chars(*it))
{
return U(0);
}
// bad leading zero
BOOST_URL_RETURN_EC(
error::invalid);
}
if(! digit_chars(*it))
{
// expected digit
BOOST_URL_RETURN_EC(
error::mismatch);
}
static constexpr U Digits10 =
std::numeric_limits<
U>::digits10;
static constexpr U ten = 10;
char const* safe_end;
if(static_cast<std::size_t>(
end - it) >= Digits10)
safe_end = it + Digits10;
else
safe_end = end;
U u = *it - '0';
++it;
while(it != safe_end &&
digit_chars(*it))
{
char const dig = *it - '0';
u = u * ten + dig;
++it;
}
if( it != end &&
digit_chars(*it))
{
static constexpr U Max = (
std::numeric_limits<
U>::max)();
static constexpr
auto div = (Max / ten);
static constexpr
char rem = (Max % ten);
char const dig = *it - '0';
if( u > div || (
u == div && dig > rem))
{
// integer overflow
BOOST_URL_RETURN_EC(
error::invalid);
}
u = u * ten + dig;
++it;
if( it < end &&
digit_chars(*it))
{
// integer overflow
BOOST_URL_RETURN_EC(
error::invalid);
}
}
return u;
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,116 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_IMPL_VARIANT_RULE_HPP
#define BOOST_URL_GRAMMAR_IMPL_VARIANT_RULE_HPP
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/parse.hpp>
#include <cstdint>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
// must come first
template<
class R0,
class... Rn,
std::size_t I>
auto
parse_variant(
char const*&,
char const*,
detail::tuple<
R0, Rn...> const&,
std::integral_constant<
std::size_t, I> const&,
std::false_type const&) ->
system::result<variant<
typename R0::value_type,
typename Rn::value_type...>>
{
// no match
BOOST_URL_RETURN_EC(
error::mismatch);
}
template<
class R0,
class... Rn,
std::size_t I>
auto
parse_variant(
char const*& it,
char const* const end,
detail::tuple<
R0, Rn...> const& rn,
std::integral_constant<
std::size_t, I> const&,
std::true_type const&) ->
system::result<variant<
typename R0::value_type,
typename Rn::value_type...>>
{
auto const it0 = it;
auto rv = parse(
it, end, get<I>(rn));
if( rv )
return variant<
typename R0::value_type,
typename Rn::value_type...>{
variant2::in_place_index_t<I>{}, *rv};
it = it0;
return parse_variant(
it, end, rn,
std::integral_constant<
std::size_t, I+1>{},
std::integral_constant<bool,
((I + 1) < (1 +
sizeof...(Rn)))>{});
}
} // detail
template<class R0, class... Rn>
auto
variant_rule_t<R0, Rn...>::
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
{
return detail::parse_variant(
it, end, rn_,
std::integral_constant<
std::size_t, 0>{},
std::true_type{});
}
//------------------------------------------------
template<class R0, class... Rn>
auto
constexpr
variant_rule(
R0 const& r0,
Rn const&... rn) noexcept ->
variant_rule_t<R0, Rn...>
{
return { r0, rn... };
}
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,88 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_LITERAL_RULE_HPP
#define BOOST_URL_GRAMMAR_LITERAL_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <cstdlib>
namespace boost {
namespace urls {
namespace grammar {
/** Match a string literal exactly
If there is no more input, or if the
end of the input is reached, and a prefix
of the literal matches exactly, the error
returned is @ref error::need_more.
@par Value Type
@code
using value_type = core::string_view;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< core::string_view > rv = parse( "HTTP", literal_rule( "HTTP" ) );
@endcode
@see
@ref delim_rule,
@ref parse.
*/
#ifdef BOOST_URL_DOCS
constexpr
__implementation_defined__
literal_rule( char const* s );
#else
class literal_rule
{
char const* s_ = nullptr;
std::size_t n_ = 0;
constexpr
static
std::size_t
len(char const* s) noexcept
{
return *s
? 1 + len(s + 1)
: 0;
}
public:
using value_type = core::string_view;
constexpr
explicit
literal_rule(
char const* s) noexcept
: s_(s)
, n_(len(s))
{
}
BOOST_URL_DECL
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept;
};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,402 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_LUT_CHARS_HPP
#define BOOST_URL_GRAMMAR_LUT_CHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
#include <cstdint>
#include <type_traits>
// Credit to Peter Dimov for ideas regarding
// SIMD constexpr, and character set masks.
namespace boost {
namespace urls {
namespace grammar {
#ifndef BOOST_URL_DOCS
namespace detail {
template<class T, class = void>
struct is_pred : std::false_type {};
template<class T>
struct is_pred<T, void_t<
decltype(
std::declval<bool&>() =
std::declval<T const&>().operator()(
std::declval<char>())
) > > : std::true_type
{
};
} // detail
#endif
/** A set of characters
The characters defined by instances of
this set are provided upon construction.
The `constexpr` implementation allows
these to become compile-time constants.
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
constexpr lut_chars vowel_chars = "AEIOU" "aeiou";
system::result< core::string_view > rv = parse( "Aiea", token_rule( vowel_chars ) );
@endcode
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
class lut_chars
{
std::uint64_t mask_[4] = {};
constexpr
static
std::uint64_t
lo(char c) noexcept
{
return static_cast<
unsigned char>(c) & 3;
}
constexpr
static
std::uint64_t
hi(char c) noexcept
{
return 1ULL << (static_cast<
unsigned char>(c) >> 2);
}
constexpr
static
lut_chars
construct(
char const* s) noexcept
{
return *s
? lut_chars(*s) +
construct(s+1)
: lut_chars();
}
constexpr
static
lut_chars
construct(
unsigned char ch,
bool b) noexcept
{
return b
? lut_chars(ch)
: lut_chars();
}
template<class Pred>
constexpr
static
lut_chars
construct(
Pred pred,
unsigned char ch) noexcept
{
return ch == 255
? construct(ch, pred(ch))
: construct(ch, pred(ch)) +
construct(pred, ch + 1);
}
constexpr
lut_chars() = default;
constexpr
lut_chars(
std::uint64_t m0,
std::uint64_t m1,
std::uint64_t m2,
std::uint64_t m3) noexcept
: mask_{ m0, m1, m2, m3 }
{
}
public:
/** Constructor
This function constructs a character
set which has as a single member,
the character `ch`.
@par Example
@code
constexpr lut_chars asterisk( '*' );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@param ch A character.
*/
constexpr
lut_chars(char ch) noexcept
: mask_ {
lo(ch) == 0 ? hi(ch) : 0,
lo(ch) == 1 ? hi(ch) : 0,
lo(ch) == 2 ? hi(ch) : 0,
lo(ch) == 3 ? hi(ch) : 0 }
{
}
/** Constructor
This function constructs a character
set which has as members, all of the
characters present in the null-terminated
string `s`.
@par Example
@code
constexpr lut_chars digits = "0123456789";
@endcode
@par Complexity
Linear in `::strlen(s)`, or constant
if `s` is a constant expression.
@par Exception Safety
Throws nothing.
@param s A null-terminated string.
*/
constexpr
lut_chars(
char const* s) noexcept
: lut_chars(construct(s))
{
}
/** Constructor.
This function constructs a character
set which has as members, every value
of `char ch` for which the expression
`pred(ch)` returns `true`.
@par Example
@code
struct is_digit
{
constexpr bool
operator()(char c ) const noexcept
{
return c >= '0' && c <= '9';
}
};
constexpr lut_chars digits( is_digit{} );
@endcode
@par Complexity
Linear in `pred`, or constant if
`pred(ch)` is a constant expression.
@par Exception Safety
Throws nothing.
@param pred The function object to
use for determining membership in
the character set.
*/
template<class Pred
#ifndef BOOST_URL_DOCS
,class = typename std::enable_if<
detail::is_pred<Pred>::value &&
! std::is_base_of<
lut_chars, Pred>::value>::type
#endif
>
constexpr
lut_chars(Pred const& pred) noexcept
: lut_chars(
construct(pred, 0))
{
}
/** Return true if ch is in the character set.
This function returns true if the
character `ch` is in the set, otherwise
it returns false.
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@param ch The character to test.
*/
constexpr
bool
operator()(
unsigned char ch) const noexcept
{
return mask_[lo(ch)] & hi(ch);
}
/** Return the union of two character sets.
This function returns a new character
set which contains all of the characters
in `cs0` as well as all of the characters
in `cs`.
@par Example
This creates a character set which
includes all letters and numbers
@code
constexpr lut_chars alpha_chars(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz");
constexpr lut_chars alnum_chars = alpha_chars + "0123456789";
@endcode
@par Complexity
Constant.
@return The new character set.
@param cs0 A character to join
@param cs1 A character to join
*/
friend
constexpr
lut_chars
operator+(
lut_chars const& cs0,
lut_chars const& cs1) noexcept
{
return lut_chars(
cs0.mask_[0] | cs1.mask_[0],
cs0.mask_[1] | cs1.mask_[1],
cs0.mask_[2] | cs1.mask_[2],
cs0.mask_[3] | cs1.mask_[3]);
}
/** Return a new character set by subtracting
This function returns a new character
set which is formed from all of the
characters in `cs0` which are not in `cs`.
@par Example
This statement declares a character set
containing all the lowercase letters
which are not vowels:
@code
constexpr lut_chars consonants = lut_chars("abcdefghijklmnopqrstuvwxyz") - "aeiou";
@endcode
@par Complexity
Constant.
@return The new character set.
@param cs0 A character set to join.
@param cs1 A character set to join.
*/
friend
constexpr
lut_chars
operator-(
lut_chars const& cs0,
lut_chars const& cs1) noexcept
{
return lut_chars(
cs0.mask_[0] & ~cs1.mask_[0],
cs0.mask_[1] & ~cs1.mask_[1],
cs0.mask_[2] & ~cs1.mask_[2],
cs0.mask_[3] & ~cs1.mask_[3]);
}
/** Return a new character set which is the complement of another character set.
This function returns a new character
set which contains all of the characters
that are not in `*this`.
@par Example
This statement declares a character set
containing everything but vowels:
@code
constexpr lut_chars not_vowels = ~lut_chars( "AEIOU" "aeiou" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@return The new character set.
*/
constexpr
lut_chars
operator~() const noexcept
{
return lut_chars(
~mask_[0],
~mask_[1],
~mask_[2],
~mask_[3]
);
}
#ifndef BOOST_URL_DOCS
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
#endif
};
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,108 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_NOT_EMPTY_RULE_HPP
#define BOOST_URL_GRAMMAR_NOT_EMPTY_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/grammar/type_traits.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Match another rule, if the result is not empty
This adapts another rule such that
when an empty string is successfully
parsed, the result is an error.
@par Value Type
@code
using value_type = typename Rule::value_type;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< decode_view > rv = parse( "Program%20Files",
not_empty_rule( pct_encoded_rule( unreserved_chars ) ) );
@endcode
@param r The rule to match
@see
@ref parse,
@ref pct_encoded_rule,
@ref unreserved_chars.
*/
#ifdef BOOST_URL_DOCS
template<class Rule>
constexpr
__implementation_defined__
not_empty_rule( Rule r );
#else
template<class R>
struct not_empty_rule_t
{
using value_type =
typename R::value_type;
auto
parse(
char const*& it,
char const* end) const ->
system::result<value_type>;
template<class R_>
friend
constexpr
auto
not_empty_rule(
R_ const& r) ->
not_empty_rule_t<R_>;
private:
constexpr
not_empty_rule_t(
R const& r) noexcept
: r_(r)
{
}
R r_;
};
template<class Rule>
auto
constexpr
not_empty_rule(
Rule const& r) ->
not_empty_rule_t<Rule>
{
// If you get a compile error here it
// means that your rule does not meet
// the type requirements. Please check
// the documentation.
static_assert(
is_rule<Rule>::value,
"Rule requirements not met");
return { r };
}
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/not_empty_rule.hpp>
#endif

View File

@@ -0,0 +1,112 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_OPTIONAL_RULE_HPP
#define BOOST_URL_GRAMMAR_OPTIONAL_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/optional.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Match a rule, or the empty string
Optional BNF elements are denoted with
square brackets. If the specified rule
returns any error it is treated as if
the rule did not match.
@par Value Type
@code
using value_type = optional< typename Rule::value_type >;
@endcode
@par Example
Rules are used with the function @ref grammar::parse.
@code
system::result< optional< core::string_view > > rv = parse( "", optional_rule( token_rule( alpha_chars ) ) );
@endcode
@par BNF
@code
optional = [ rule ]
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.8"
>3.8. Optional Sequence (rfc5234)</a>
@param r The rule to match
@see
@ref alpha_chars,
@ref parse,
@ref optional,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
template<class Rule>
constexpr
__implementation_defined__
optional_rule( Rule r ) noexcept;
#else
template<class Rule>
struct optional_rule_t
: private empty_value<Rule>
{
using value_type = boost::optional<
typename Rule::value_type>;
system::result<value_type>
parse(
char const*& it,
char const* end) const;
template<class R_>
friend
constexpr
auto
optional_rule(
R_ const& r) ->
optional_rule_t<R_>;
private:
constexpr
optional_rule_t(
Rule const& r) noexcept
: empty_value<Rule>(
empty_init,
r)
{
}
};
template<class Rule>
auto
constexpr
optional_rule(
Rule const& r) ->
optional_rule_t<Rule>
{
return { r };
}
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/optional_rule.hpp>
#endif

View File

@@ -0,0 +1,144 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_PARSE_HPP
#define BOOST_URL_GRAMMAR_PARSE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/type_traits.hpp>
namespace boost {
namespace urls {
namespace grammar {
//------------------------------------------------
/** Parse a character buffer using a rule
@param it A pointer to the start. The
caller's variable is changed to
reflect the amount of input consumed.
@param end A pointer to the end.
@param r The rule to use
@return The parsed value upon success,
otherwise an error.
@see
@ref result.
*/
template<class Rule>
system::result<typename Rule::value_type>
parse(
char const*& it,
char const* end,
Rule const& r);
/** Parse a character buffer using a rule
This function parses a complete string into
the specified sequence of rules. If the
string is not completely consumed, an
error is returned instead.
@param s The input string
@param r The rule to use
@return The parsed value upon success,
otherwise an error.
@see
@ref result.
*/
template<class Rule>
system::result<typename Rule::value_type>
parse(
core::string_view s,
Rule const& r);
//------------------------------------------------
#ifndef BOOST_URL_DOCS
namespace detail {
template<class Rule>
struct rule_ref
{
Rule const& r_;
using value_type =
typename Rule::value_type;
system::result<value_type>
parse(
char const*& it,
char const* end) const
{
return r_.parse(it, end);
}
};
} // detail
#endif
/** Return a reference to a rule
This function returns a rule which
references the specified object. This is
used to reduce the number of bytes of
storage (`sizeof`) required by a combinator
when it stores a copy of the object.
<br>
Ownership of the object is not transferred;
the caller is responsible for ensuring the
lifetime of the object is extended until it
is no longer referenced. For best results,
`ref` should only be used with compile-time
constants.
@param r The rule to use
*/
template<class Rule>
constexpr
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
typename std::enable_if<
is_rule<Rule>::value &&
! std::is_same<Rule,
detail::rule_ref<Rule> >::value,
detail::rule_ref<Rule> >::type
#endif
ref(Rule const& r) noexcept
{
return detail::rule_ref<
Rule>{r};
}
#ifndef BOOST_URL_DOCS
// If you get a compile error here it
// means you called ref with something
// that is not a CharSet or Rule!
constexpr
void
ref(...) = delete;
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/parse.hpp>
#endif

View File

@@ -0,0 +1,602 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
#define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/parse.hpp>
#include <boost/url/grammar/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <stddef.h> // ::max_align_t
namespace boost {
namespace urls {
namespace grammar {
/** A forward range of parsed elements
Objects of this type are forward ranges
returned when parsing using the
@ref range_rule.
Iteration is performed by re-parsing the
underlying character buffer. Ownership
of the buffer is not transferred; the
caller is responsible for ensuring that
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
@ref parse,
@ref range_rule.
*/
template<class T>
class range
{
// buffer size for type-erased rule
static constexpr
std::size_t BufferSize = 128;
struct small_buffer
{
alignas(alignof(::max_align_t))
unsigned char buf[BufferSize];
void const* addr() const noexcept
{
return buf;
}
void* addr() noexcept
{
return buf;
}
};
small_buffer sb_;
core::string_view s_;
std::size_t n_ = 0;
//--------------------------------------------
struct any_rule;
template<class R, bool>
struct impl1;
template<
class R0, class R1, bool>
struct impl2;
template<
class R0, class R1>
friend struct range_rule_t;
any_rule&
get() noexcept
{
return *reinterpret_cast<
any_rule*>(sb_.addr());
}
any_rule const&
get() const noexcept
{
return *reinterpret_cast<
any_rule const*>(
sb_.addr());
}
template<class R>
range(
core::string_view s,
std::size_t n,
R const& r);
template<
class R0, class R1>
range(
core::string_view s,
std::size_t n,
R0 const& first,
R1 const& next);
public:
/** The type of each element of the range
*/
using value_type = T;
/** The type of each element of the range
*/
using reference = T const&;
/** The type of each element of the range
*/
using const_reference = T const&;
/** Provided for compatibility, unused
*/
using pointer = void const*;
/** The type used to represent unsigned integers
*/
using size_type = std::size_t;
/** The type used to represent signed integers
*/
using difference_type = std::ptrdiff_t;
/** A constant, forward iterator to elements of the range
*/
class iterator;
/** A constant, forward iterator to elements of the range
*/
using const_iterator = iterator;
/** Destructor
*/
~range();
/** Constructor
Default-constructed ranges have
zero elements.
@par Exception Safety
Throws nothing.
*/
range() noexcept;
/** Constructor
The new range references the
same underlying character buffer.
Ownership is not transferred; the
caller is responsible for ensuring
that the lifetime of the buffer
extends until it is no longer
referenced. The moved-from object
becomes as if default-constructed.
@par Exception Safety
Throws nothing.
*/
range(range&&) noexcept;
/** Constructor
The copy references the same
underlying character buffer.
Ownership is not transferred; the
caller is responsible for ensuring
that the lifetime of the buffer
extends until it is no longer
referenced.
@par Exception Safety
Throws nothing.
*/
range(range const&) noexcept;
/** Constructor
After the move, this references the
same underlying character buffer. Ownership
is not transferred; the caller is responsible
for ensuring that the lifetime of the buffer
extends until it is no longer referenced.
The moved-from object becomes as if
default-constructed.
@par Exception Safety
Throws nothing.
*/
range&
operator=(range&&) noexcept;
/** Assignment
The copy references the same
underlying character buffer.
Ownership is not transferred; the
caller is responsible for ensuring
that the lifetime of the buffer
extends until it is no longer
referenced.
@par Exception Safety
Throws nothing.
*/
range&
operator=(range const&) noexcept;
/** Return an iterator to the beginning
*/
iterator begin() const noexcept;
/** Return an iterator to the end
*/
iterator end() const noexcept;
/** Return true if the range is empty
*/
bool
empty() const noexcept
{
return n_ == 0;
}
/** Return the number of elements in the range
*/
std::size_t
size() const noexcept
{
return n_;
}
/** Return the matching part of the string
*/
core::string_view
string() const noexcept
{
return s_;
}
};
//------------------------------------------------
#ifndef BOOST_URL_DOCS
template<
class R0,
class R1 = void>
struct range_rule_t;
#endif
//------------------------------------------------
/** Match a repeating number of elements
Elements are matched using the passed rule.
<br>
Normally when the rule returns an error,
the range ends and the input is rewound to
one past the last character that matched
successfully. However, if the rule returns
the special value @ref error::end_of_range, the
input is not rewound. This allows for rules
which consume input without producing
elements in the range. For example, to
relax the grammar for a comma-delimited
list by allowing extra commas in between
elements.
@par Value Type
@code
using value_type = range< typename Rule::value_type >;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
// range = 1*( ";" token )
system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
range_rule(
tuple_rule(
squelch( delim_rule( ';' ) ),
token_rule( alpha_chars ) ),
1 ) );
@endcode
@par BNF
@code
range = <N>*<M>next
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
>3.6. Variable Repetition (rfc5234)</a>
@param next The rule to use for matching
each element. The range extends until this
rule returns an error.
@param N The minimum number of elements for
the range to be valid. If omitted, this
defaults to zero.
@param M The maximum number of elements for
the range to be valid. If omitted, this
defaults to unlimited.
@see
@ref alpha_chars,
@ref delim_rule,
@ref error::end_of_range,
@ref parse,
@ref range,
@ref tuple_rule,
@ref squelch.
*/
#ifdef BOOST_URL_DOCS
template<class Rule>
constexpr
__implementation_defined__
range_rule(
Rule next,
std::size_t N = 0,
std::size_t M =
std::size_t(-1)) noexcept;
#else
template<class R>
struct range_rule_t<R>
{
using value_type =
range<typename R::value_type>;
system::result<value_type>
parse(
char const*& it,
char const* end) const;
private:
constexpr
range_rule_t(
R const& next,
std::size_t N,
std::size_t M) noexcept
: next_(next)
, N_(N)
, M_(M)
{
}
template<class R_>
friend
constexpr
range_rule_t<R_>
range_rule(
R_ const& next,
std::size_t N,
std::size_t M) noexcept;
R const next_;
std::size_t N_;
std::size_t M_;
};
template<class Rule>
constexpr
range_rule_t<Rule>
range_rule(
Rule const& next,
std::size_t N = 0,
std::size_t M =
std::size_t(-1)) noexcept
{
// If you get a compile error here it
// means that your rule does not meet
// the type requirements. Please check
// the documentation.
static_assert(
is_rule<Rule>::value,
"Rule requirements not met");
return range_rule_t<Rule>{
next, N, M};
}
#endif
//------------------------------------------------
/** Match a repeating number of elements
Two rules are used for match. The rule
`first` is used for matching the first
element, while the `next` rule is used
to match every subsequent element.
<br>
Normally when the rule returns an error,
the range ends and the input is rewound to
one past the last character that matched
successfully. However, if the rule returns
the special value @ref error::end_of_range, the
input is not rewound. This allows for rules
which consume input without producing
elements in the range. For example, to
relax the grammar for a comma-delimited
list by allowing extra commas in between
elements.
@par Value Type
@code
using value_type = range< typename Rule::value_type >;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
// range = [ token ] *( "," token )
system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
range_rule(
token_rule( alpha_chars ), // first
tuple_rule( // next
squelch( delim_rule(',') ),
token_rule( alpha_chars ) ) ) );
@endcode
@par BNF
@code
range = <1>*<1>first
/ first <N-1>*<M-1>next
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
>3.6. Variable Repetition (rfc5234)</a>
@param first The rule to use for matching
the first element. If this rule returns
an error, the range is empty.
@param next The rule to use for matching
each subsequent element. The range extends
until this rule returns an error.
@param N The minimum number of elements for
the range to be valid. If omitted, this
defaults to zero.
@param M The maximum number of elements for
the range to be valid. If omitted, this
defaults to unlimited.
@see
@ref alpha_chars,
@ref delim_rule,
@ref error::end_of_range,
@ref parse,
@ref range,
@ref tuple_rule,
@ref squelch.
*/
#ifdef BOOST_URL_DOCS
template<
class Rule1, class Rule2>
constexpr
__implementation_defined__
range_rule(
Rule1 first,
Rule2 next,
std::size_t N = 0,
std::size_t M =
std::size_t(-1)) noexcept;
#else
template<class R0, class R1>
struct range_rule_t
{
using value_type =
range<typename R0::value_type>;
system::result<value_type>
parse(
char const*& it,
char const* end) const;
private:
constexpr
range_rule_t(
R0 const& first,
R1 const& next,
std::size_t N,
std::size_t M) noexcept
: first_(first)
, next_(next)
, N_(N)
, M_(M)
{
}
template<
class R0_, class R1_>
friend
constexpr
auto
range_rule(
R0_ const& first,
R1_ const& next,
std::size_t N,
std::size_t M) noexcept ->
#if 1
typename std::enable_if<
! std::is_integral<R1_>::value,
range_rule_t<R0_, R1_>>::type;
#else
range_rule_t<R0_, R1_>;
#endif
R0 const first_;
R1 const next_;
std::size_t N_;
std::size_t M_;
};
template<
class Rule1, class Rule2>
constexpr
auto
range_rule(
Rule1 const& first,
Rule2 const& next,
std::size_t N = 0,
std::size_t M =
std::size_t(-1)) noexcept ->
#if 1
typename std::enable_if<
! std::is_integral<Rule2>::value,
range_rule_t<Rule1, Rule2>>::type
#else
range_rule_t<Rule1, Rule2>
#endif
{
// If you get a compile error here it
// means that your rule does not meet
// the type requirements. Please check
// the documentation.
static_assert(
is_rule<Rule1>::value,
"Rule requirements not met");
static_assert(
is_rule<Rule2>::value,
"Rule requirements not met");
// If you get a compile error here it
// means that your rules do not have
// the exact same value_type. Please
// check the documentation.
static_assert(
std::is_same<
typename Rule1::value_type,
typename Rule2::value_type>::value,
"Rule requirements not met");
return range_rule_t<Rule1, Rule2>{
first, next, N, M};
}
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/range_rule.hpp>
#endif

View File

@@ -0,0 +1,510 @@
//
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_RECYCLED_HPP
#define BOOST_URL_GRAMMAR_RECYCLED_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/recycled.hpp>
#include <atomic>
#include <cstddef>
#include <type_traits>
#include <stddef.h> // ::max_align_t
#if !defined(BOOST_URL_DISABLE_THREADS)
# include <mutex>
#endif
namespace boost {
namespace urls {
namespace grammar {
/** Provides an aligned storage buffer aligned for T
*/
#ifdef BOOST_URL_DOCS
template<class T>
struct aligned_storage
{
/** Return a pointer to the aligned storage area
*/
void* addr() noexcept;
/** Return a pointer to the aligned storage area
*/
void const* addr() const noexcept;
};
#else
template<class T>
using aligned_storage =
detail::aligned_storage_impl<
detail::nearest_pow2(sizeof(T), 64),
(alignof(::max_align_t) > alignof(T)) ?
alignof(::max_align_t) : alignof(T)>;
#endif
//------------------------------------------------
/** A thread-safe collection of instances of T
Instances of this type may be used to control
where recycled instances of T come from when
used with @ref recycled_ptr.
@par Example
@code
static recycled< std::string > bin;
recycled_ptr< std::string > ps( bin );
// Put the string into a known state
ps->clear();
@endcode
@see
@ref recycled_ptr.
*/
template<class T>
class recycled
{
public:
/** Destructor
All recycled instances of T are destroyed.
Undefined behavior results if there are
any @ref recycled_ptr which reference
this recycle bin.
*/
~recycled();
/** Constructor
*/
constexpr recycled() = default;
private:
template<class>
friend class recycled_ptr;
struct U
{
T t;
U* next = nullptr;
#if !defined(BOOST_URL_DISABLE_THREADS)
std::atomic<
std::size_t> refs;
#else
std::size_t refs;
#endif
U()
: refs{1}
{
}
};
struct report;
U* acquire();
void release(U* u) noexcept;
U* head_ = nullptr;
#if !defined(BOOST_URL_DISABLE_THREADS)
std::mutex m_;
#endif
};
//------------------------------------------------
/** A pointer to shared instance of T
This is a smart pointer container which can
acquire shared ownership of an instance of
`T` upon or after construction. The instance
is guaranteed to be in a valid, but unknown
state. Every recycled pointer references
a valid recycle bin.
@par Example
@code
static recycled< std::string > bin;
recycled_ptr< std::string > ps( bin );
// Put the string into a known state
ps->clear();
@endcode
@tparam T the type of object to
acquire, which must be
<em>DefaultConstructible</em>.
*/
template<class T>
class recycled_ptr
{
// T must be default constructible!
static_assert(
std::is_default_constructible<T>::value,
"T must be DefaultConstructible");
friend class recycled<T>;
using B = recycled<T>;
using U = typename B::U;
B* bin_ = nullptr;
U* p_ = nullptr;
public:
/** Destructor
If this is not empty, shared ownership
of the pointee is released. If this was
the last reference, the object is
returned to the original recycle bin.
@par Effects
@code
this->release();
@endcode
*/
~recycled_ptr();
/** Constructor
Upon construction, this acquires
exclusive access to an object of type
`T` which is either recycled from the
specified bin, or newly allocated.
The object is in an unknown but
valid state.
@par Example
@code
static recycled< std::string > bin;
recycled_ptr< std::string > ps( bin );
// Put the string into a known state
ps->clear();
@endcode
@par Postconditions
@code
&this->bin() == &bin && ! this->empty()
@endcode
@param bin The recycle bin to use
@see
@ref recycled.
*/
explicit
recycled_ptr(recycled<T>& bin);
/** Constructor
After construction, this is empty and
refers to the specified recycle bin.
@par Example
@code
static recycled< std::string > bin;
recycled_ptr< std::string > ps( bin, nullptr );
// Acquire a string and put it into a known state
ps->acquire();
ps->clear();
@endcode
@par Postconditions
@code
&this->bin() == &bin && this->empty()
@endcode
@par Exception Safety
Throws nothing.
@param bin The recycle bin to use
@see
@ref acquire,
@ref recycled,
@ref release.
*/
recycled_ptr(
recycled<T>& bin,
std::nullptr_t) noexcept;
/** Constructor
Upon construction, this acquires
exclusive access to an object of type
`T` which is either recycled from a
global recycle bin, or newly allocated.
The object is in an unknown but
valid state.
@par Example
@code
recycled_ptr< std::string > ps;
// Put the string into a known state
ps->clear();
@endcode
@par Postconditions
@code
&this->bin() != nullptr && ! this->empty()
@endcode
@see
@ref recycled.
*/
recycled_ptr();
/** Constructor
After construction, this is empty
and refers to a global recycle bin.
@par Example
@code
recycled_ptr< std::string > ps( nullptr );
// Acquire a string and put it into a known state
ps->acquire();
ps->clear();
@endcode
@par Postconditions
@code
&this->bin() != nullptr && this->empty()
@endcode
@par Exception Safety
Throws nothing.
@see
@ref acquire,
@ref recycled,
@ref release.
*/
recycled_ptr(
std::nullptr_t) noexcept;
/** Constructor
If `other` references an object, the
newly constructed pointer acquires
shared ownership. Otherwise this is
empty. The new pointer references
the same recycle bin as `other`.
@par Postconditions
@code
&this->bin() == &other->bin() && this->get() == other.get()
@endcode
@par Exception Safety
Throws nothing.
@param other The pointer to copy
*/
recycled_ptr(
recycled_ptr const& other) noexcept;
/** Constructor
If `other` references an object,
ownership is transferred including
a reference to the recycle bin. After
the move, the moved-from object is empty.
@par Postconditions
@code
&this->bin() == &other->bin() && ! this->empty() && other.empty()
@endcode
@par Exception Safety
Throws nothing.
@param other The pointer to move from
*/
recycled_ptr(
recycled_ptr&& other) noexcept;
/** Assignment
If `other` references an object,
ownership is transferred including
a reference to the recycle bin. After
the move, the moved-from object is empty.
@par Effects
@code
this->release()
@endcode
@par Postconditions
@code
&this->bin() == &other->bin()
@endcode
@par Exception Safety
Throws nothing.
@param other The pointer to move from
*/
recycled_ptr&
operator=(
recycled_ptr&& other) noexcept;
/** Assignment
If `other` references an object,
this acquires shared ownership and
references the same recycle bin as
`other`. The previous object if any
is released.
@par Effects
@code
this->release()
@endcode
@par Postconditions
@code
&this->bin() == &other->bin() && this->get() == other.get()
@endcode
@par Exception Safety
Throws nothing.
@param other The pointer to copy from
*/
recycled_ptr&
operator=(
recycled_ptr const& other) noexcept;
/** Return true if this does not reference an object
@par Exception Safety
Throws nothing.
*/
bool
empty() const noexcept
{
return p_ == nullptr;
}
/** Return true if this references an object
@par Effects
@code
return ! this->empty();
@endcode
@par Exception Safety
Throws nothing.
*/
explicit
operator bool() const noexcept
{
return p_ != nullptr;
}
/** Return the referenced recycle bin
@par Exception Safety
Throws nothing.
*/
recycled<T>&
bin() const noexcept
{
return *bin_;
}
/** Return the referenced object
If this is empty, `nullptr` is returned.
@par Exception Safety
Throws nothing.
*/
T* get() const noexcept
{
return &p_->t;
}
/** Return the referenced object
If this is empty, `nullptr` is returned.
@par Exception Safety
Throws nothing.
*/
T* operator->() const noexcept
{
return get();
}
/** Return the referenced object
@par Preconditions
@code
not this->empty()
@endcode
*/
T& operator*() const noexcept
{
return *get();
}
/** Return the referenced object
If this references an object, it is
returned. Otherwise, exclusive ownership
of a new object of type `T` is acquired
and returned.
@par Postconditions
@code
not this->empty()
@endcode
*/
T& acquire();
/** Release the referenced object
If this references an object, it is
released to the referenced recycle bin.
The pointer continues to reference
the same recycle bin.
@par Postconditions
@code
this->empty()
@endcode
@par Exception Safety
Throws nothing.
*/
void release() noexcept;
};
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/recycled.hpp>
#endif

View File

@@ -0,0 +1,347 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
#define BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
#include <boost/url/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/detail/except.hpp>
#include <memory>
#include <string>
namespace boost {
namespace urls {
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 accepts 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
virtual ~arg() = default;
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, 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_length_error();
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_to(
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 core::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 = core::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 core::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
namespace grammar {
namespace string_token = ::boost::urls::string_token;
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,877 @@
//
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_STRING_VIEW_BASE_HPP
#define BOOST_URL_GRAMMAR_STRING_VIEW_BASE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/detail/string_view.hpp>
#include <boost/core/detail/string_view.hpp>
#include <cstddef>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
namespace boost {
namespace urls {
namespace grammar {
/** Common functionality for string views
This base class is used to provide common
member functions for reference types that
behave like string views. This cannot be
instantiated directly; Instead, derive
from the type and provide constructors
which offer any desired preconditions
and invariants.
*/
class string_view_base
{
protected:
/** The referenced character buffer
*/
core::string_view s_;
/** Constructor
*/
constexpr
string_view_base(
core::string_view s) noexcept
: s_(s)
{
}
/** Constructor
*/
constexpr
string_view_base(
char const* data,
std::size_t size) noexcept
: s_(data, size)
{
}
/** Swap
*/
// VFALCO No idea why this fails in msvc
/*BOOST_CXX14_CONSTEXPR*/ void swap(
string_view_base& s ) noexcept
{
std::swap(s_, s.s_);
}
/** Constructor
*/
string_view_base() = default;
/** Constructor
*/
string_view_base(
string_view_base const&) = default;
/** Assignment
*/
string_view_base& operator=(
string_view_base const&) = default;
public:
/// The character traits
typedef std::char_traits<char> traits_type;
/// The value type
typedef char value_type;
/// The pointer type
typedef char* pointer;
/// The const pointer type
typedef char const* const_pointer;
/// The reference type
typedef char& reference;
/// The const reference type
typedef char const& const_reference;
/// The const iterator type
typedef char const* const_iterator;
/// The iterator type
typedef const_iterator iterator;
/// The const reverse iterator type
typedef std::reverse_iterator<
const_iterator> const_reverse_iterator;
/// The reverse iterator type
typedef const_reverse_iterator reverse_iterator;
/// The size type
typedef std::size_t size_type;
/// The difference type
typedef std::ptrdiff_t difference_type;
/// A constant used to represent "no position"
static constexpr std::size_t npos = core::string_view::npos;
//--------------------------------------------
/** Conversion
*/
operator
core::string_view() const noexcept
{
return s_;
}
/** Conversion
*/
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
operator
std::string_view() const noexcept
{
return std::string_view(s_);
}
#endif
/** Conversion
Conversion to std::string is explicit
because assigning to string using an
implicit constructor does not preserve
capacity.
*/
explicit
operator
std::string() const noexcept
{
return std::string(s_);
}
//--------------------------------------------
// iterator support
/** Return an iterator to the beginning
See `core::string_view::begin`
*/
BOOST_CONSTEXPR const_iterator begin() const noexcept
{
return s_.begin();
}
/** Return an iterator to the end
See `core::string_view::end`
*/
BOOST_CONSTEXPR const_iterator end() const noexcept
{
return s_.end();
}
/** Return an iterator to the beginning
See `core::string_view::cbegin`
*/
BOOST_CONSTEXPR const_iterator cbegin() const noexcept
{
return s_.cbegin();
}
/** Return an iterator to the end
See `core::string_view::cend`
*/
BOOST_CONSTEXPR const_iterator cend() const noexcept
{
return s_.cend();
}
/** Return a reverse iterator to the end
See `core::string_view::rbegin`
*/
#ifdef __cpp_lib_array_constexpr
constexpr
#endif
const_reverse_iterator rbegin() const noexcept
{
return s_.rbegin();
}
/** Return a reverse iterator to the beginning
See `core::string_view::rend`
*/
#ifdef __cpp_lib_array_constexpr
constexpr
#endif
const_reverse_iterator rend() const noexcept
{
return s_.rend();
}
/** Return a reverse iterator to the end
See `core::string_view::crbegin`
*/
#ifdef __cpp_lib_array_constexpr
constexpr
#endif
const_reverse_iterator crbegin() const noexcept
{
return s_.crbegin();
}
/** Return a reverse iterator to the beginning
See `core::string_view::crend`
*/
#ifdef __cpp_lib_array_constexpr
constexpr
#endif
const_reverse_iterator crend() const noexcept
{
return s_.crend();
}
// capacity
/** Return the size
See `core::string_view::size`
*/
BOOST_CONSTEXPR size_type size() const noexcept
{
return s_.size();
}
/** Return the size
See `core::string_view::length`
*/
BOOST_CONSTEXPR size_type length() const noexcept
{
return s_.length();
}
/** Return the maximum allowed size
See `core::string_view::max_size`
*/
BOOST_CONSTEXPR size_type max_size() const noexcept
{
return s_.max_size();
}
/** Return true if the string is empty
See `core::string_view::size`
*/
BOOST_CONSTEXPR bool empty() const noexcept
{
return s_.empty();
}
// element access
/** Access a character
See `core::string_view::operator[]`
*/
BOOST_CXX14_CONSTEXPR const_reference
operator[]( size_type pos ) const noexcept
{
return s_[pos];
}
/** Access a character
See `core::string_view::at`
*/
BOOST_CXX14_CONSTEXPR const_reference
at( size_type pos ) const
{
return s_.at(pos);
}
/** Return the first character
See `core::string_view::front`
*/
BOOST_CXX14_CONSTEXPR const_reference
front() const noexcept
{
return s_.front();
}
/** Return the last character
See `core::string_view::back`
*/
BOOST_CXX14_CONSTEXPR const_reference
back() const noexcept
{
return s_.back();
}
/** Return a pointer to the character buffer
See `core::string_view::data`
*/
BOOST_CONSTEXPR const_pointer
data() const noexcept
{
return s_.data();
}
// string operations
/** Copy the characters to another buffer
See `core::string_view::copy`
*/
BOOST_CXX14_CONSTEXPR size_type copy(
char* s, size_type n, size_type pos = 0 ) const
{
return s_.copy(s, n, pos);
}
/** Return a view to part of the string
See `core::string_view::substr`
*/
BOOST_CXX14_CONSTEXPR core::string_view substr(
size_type pos = 0, size_type n = core::string_view::npos ) const
{
return s_.substr(pos, n);
}
// comparison
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CXX14_CONSTEXPR int
compare( core::string_view str ) const noexcept
{
return s_.compare(str);
}
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CONSTEXPR int compare(
size_type pos1, size_type n1, core::string_view str ) const
{
return s_.compare(pos1, n1, str);
}
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CONSTEXPR int compare(
size_type pos1, size_type n1, core::string_view str,
size_type pos2, size_type n2 ) const
{
return s_.compare(pos1, n1, str, pos2, n2);
}
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CONSTEXPR int compare(
char const* s ) const noexcept
{
return s_.compare(s);
}
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CONSTEXPR int compare(
size_type pos1, size_type n1, char const* s ) const
{
return s_.compare(pos1, n1, s);
}
/** Return the result of comparing to another string
See `core::string_view::compare`
*/
BOOST_CONSTEXPR int compare(
size_type pos1, size_type n1,
char const* s, size_type n2 ) const
{
return s_.compare(pos1, n1, s, n2);
}
// starts_with
/** Return true if a matching prefix exists
See `core::string_view::starts_with`
*/
BOOST_CONSTEXPR bool starts_with(
core::string_view x ) const noexcept
{
return s_.starts_with(x);
}
/** Return true if a matching prefix exists
See `core::string_view::starts_with`
*/
BOOST_CONSTEXPR bool starts_with(
char x ) const noexcept
{
return s_.starts_with(x);
}
/** Return true if a matching prefix exists
See `core::string_view::starts_with`
*/
BOOST_CONSTEXPR bool starts_with(
char const* x ) const noexcept
{
return s_.starts_with(x);
}
// ends_with
/** Return true if a matching suffix exists
See `core::string_view::ends_with`
*/
BOOST_CONSTEXPR bool ends_with(
core::string_view x ) const noexcept
{
return s_.ends_with(x);
}
/** Return true if a matching suffix exists
See `core::string_view::ends_with`
*/
BOOST_CONSTEXPR bool ends_with(
char x ) const noexcept
{
return s_.ends_with(x);
}
/** Return true if a matching suffix exists
See `core::string_view::ends_with`
*/
BOOST_CONSTEXPR bool ends_with(
char const* x ) const noexcept
{
return s_.ends_with(x);
}
// find
/** Return the position of matching characters
See `core::string_view::find`
*/
BOOST_CONSTEXPR size_type find(
core::string_view str, size_type pos = 0 ) const noexcept
{
return s_.find(str, pos);
}
/** Return the position of matching characters
See `core::string_view::find`
*/
BOOST_CXX14_CONSTEXPR size_type find(
char c, size_type pos = 0 ) const noexcept
{
return s_.find(c, pos);
}
/** Return the position of matching characters
See `core::string_view::find`
*/
BOOST_CXX14_CONSTEXPR size_type find(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.find(s, pos, n);
}
/** Return the position of matching characters
See `core::string_view::find`
*/
BOOST_CONSTEXPR size_type find(
char const* s, size_type pos = 0 ) const noexcept
{
return s_.find(s, pos);
}
// rfind
/** Return the position of matching characters
See `core::string_view::rfind`
*/
BOOST_CONSTEXPR size_type rfind(
core::string_view str, size_type pos = core::string_view::npos ) const noexcept
{
return s_.rfind(str, pos);
}
/** Return the position of matching characters
See `core::string_view::rfind`
*/
BOOST_CXX14_CONSTEXPR size_type rfind(
char c, size_type pos = core::string_view::npos ) const noexcept
{
return s_.rfind(c, pos);
}
/** Return the position of matching characters
See `core::string_view::rfind`
*/
BOOST_CXX14_CONSTEXPR size_type rfind(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.rfind(s, pos, n);
}
/** Return the position of matching characters
See `core::string_view::rfind`
*/
BOOST_CONSTEXPR size_type rfind(
char const* s, size_type pos = core::string_view::npos ) const noexcept
{
return s_.rfind(s, pos);
}
// find_first_of
/** Return the position of the first match
See `core::string_view::find_first_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_of(
core::string_view str, size_type pos = 0 ) const noexcept
{
return s_.find_first_of(str, pos);
}
/** Return the position of the first match
See `core::string_view::find_first_of`
*/
BOOST_CONSTEXPR size_type find_first_of(
char c, size_type pos = 0 ) const noexcept
{
return s_.find_first_of(c, pos);
}
/** Return the position of the first match
See `core::string_view::find_first_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_of(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.find_first_of(s, pos, n);
}
/** Return the position of the first match
See `core::string_view::find_first_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_of(
char const* s, size_type pos = 0 ) const noexcept
{
return s_.find_first_of(s, pos);
}
// find_last_of
/** Return the position of the last match
See `core::string_view::find_last_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_of(
core::string_view str, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_of(str, pos);
}
/** Return the position of the last match
See `core::string_view::find_last_of`
*/
BOOST_CONSTEXPR size_type find_last_of(
char c, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_of(c, pos);
}
/** Return the position of the last match
See `core::string_view::find_last_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_of(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.find_last_of(s, pos, n);
}
/** Return the position of the last match
See `core::string_view::find_last_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_of(
char const* s, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_of(s, pos);
}
// find_first_not_of
/** Return the position of the first non-match
See `core::string_view::find_first_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_not_of(
core::string_view str, size_type pos = 0 ) const noexcept
{
return s_.find_first_not_of(str, pos);
}
/** Return the position of the first non-match
See `core::string_view::find_first_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_not_of(
char c, size_type pos = 0 ) const noexcept
{
return s_.find_first_not_of(c, pos);
}
/** Return the position of the first non-match
See `core::string_view::find_first_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_not_of(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.find_first_not_of(s, pos, n);
}
/** Return the position of the first non-match
See `core::string_view::find_first_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_first_not_of(
char const* s, size_type pos = 0 ) const noexcept
{
return s_.find_first_not_of(s, pos);
}
// find_last_not_of
/** Return the position of the last non-match
See `core::string_view::find_last_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_not_of(
core::string_view str, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_not_of(str, pos);
}
/** Return the position of the last non-match
See `core::string_view::find_last_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_not_of(
char c, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_not_of(c, pos);
}
/** Return the position of the last non-match
See `core::string_view::find_last_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_not_of(
char const* s, size_type pos, size_type n ) const noexcept
{
return s_.find_last_not_of(s, pos, n);
}
/** Return the position of the last non-match
See `core::string_view::find_last_not_of`
*/
BOOST_CXX14_CONSTEXPR size_type find_last_not_of(
char const* s, size_type pos = core::string_view::npos ) const noexcept
{
return s_.find_last_not_of(s, pos);
}
// contains
/** Return true if matching characters are found
See `core::string_view::contains`
*/
BOOST_CONSTEXPR bool contains( core::string_view sv ) const noexcept
{
return s_.contains(sv);
}
/** Return true if matching characters are found
See `core::string_view::contains`
*/
BOOST_CXX14_CONSTEXPR bool contains( char c ) const noexcept
{
return s_.contains(c);
}
/** Return true if matching characters are found
See `core::string_view::contains`
*/
BOOST_CONSTEXPR bool contains( char const* s ) const noexcept
{
return s_.contains(s);
}
// relational operators
#ifndef BOOST_URL_DOCS
private:
template<class S0, class S1>
using is_match = std::integral_constant<bool,
std::is_convertible<S0, core::string_view>::value &&
std::is_convertible<S1, core::string_view>::value && (
(std::is_base_of<string_view_base,
typename std::decay<S0>::type>::value &&
std::is_convertible<S0 const volatile*,
string_view_base const volatile*>::value) ||
(std::is_base_of<string_view_base,
typename std::decay<S1>::type>::value &&
std::is_convertible<S1 const volatile*,
string_view_base const volatile*>::value))>;
public:
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator==(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) == urls::detail::to_sv(s1);
}
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator!=(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) != urls::detail::to_sv(s1);
}
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator<(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) < urls::detail::to_sv(s1);
}
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator<=(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) <= urls::detail::to_sv(s1);
}
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator>(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) > urls::detail::to_sv(s1);
}
template<class S0, class S1>
BOOST_CXX14_CONSTEXPR friend auto operator>=(
S0 const& s0, S1 const& s1) noexcept ->
typename std::enable_if<
is_match<S0, S1>::value, bool>::type
{
return urls::detail::to_sv(s0) >= urls::detail::to_sv(s1);
}
#endif
//--------------------------------------------
/** Return the hash of this value
*/
friend
std::size_t
hash_value(
string_view_base const& s) noexcept
{
return hash_value(s.s_);
}
BOOST_URL_DECL
friend
std::ostream&
operator<<(
std::ostream& os,
string_view_base const& s);
};
//------------------------------------------------
/** Format a string to an output stream
*/
BOOST_URL_DECL
std::ostream&
operator<<(
std::ostream& os,
string_view_base const& s);
} // grammar
#ifndef BOOST_URL_DOCS
namespace detail {
template <>
inline
core::string_view
to_sv(grammar::string_view_base const& s) noexcept
{
return s.operator core::string_view();
}
} // detail
#endif
} // urls
} // boost
#endif

View File

@@ -0,0 +1,108 @@
//
// Copyright (c) 2016-2019 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/boostorg/http_proto
//
#ifndef BOOST_URL_GRAMMAR_TOKEN_RULE_HPP
#define BOOST_URL_GRAMMAR_TOKEN_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/charset.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Match a non-empty string of characters from a set
If there is no more input, the error code
@ref error::need_more is returned.
@par Value Type
@code
using value_type = core::string_view;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< core::string_view > rv = parse( "abcdef", token_rule( alpha_chars ) );
@endcode
@par BNF
@code
token = 1*( ch )
@endcode
@param cs The character set to use
@see
@ref alpha_chars,
@ref parse.
*/
#ifdef BOOST_URL_DOCS
template<class CharSet>
constexpr
__implementation_defined__
token_rule(
CharSet cs) noexcept;
#else
template<class CharSet>
struct token_rule_t
{
using value_type = core::string_view;
static_assert(
is_charset<CharSet>::value,
"CharSet requirements not met");
auto
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>;
private:
template<class CharSet_>
friend
constexpr
auto
token_rule(
CharSet_ const&) noexcept ->
token_rule_t<CharSet_>;
constexpr
token_rule_t(
CharSet const& cs) noexcept
: cs_(cs)
{
}
CharSet const cs_;
};
template<class CharSet>
constexpr
auto
token_rule(
CharSet const& cs) noexcept ->
token_rule_t<CharSet>
{
return {cs};
}
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/token_rule.hpp>
#endif

View File

@@ -0,0 +1,248 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
#define BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/detail/tuple.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/core/empty_value.hpp>
#include <tuple>
namespace boost {
namespace urls {
namespace grammar {
/** Match a series of rules in order
This matches a series of rules in the
order specified. Upon success the input
is adjusted to point to the first
unconsumed character. There is no
implicit specification of linear white
space between each rule.
@par Value Type
@code
using value_type = __see_below__;
@endcode
The sequence rule usually returns a
`std::tuple` containing the the `value_type`
of each corresponding rule in the sequence,
except that `void` values are removed.
However, if there is exactly one non-void
value type `T`, then the sequence rule
returns `system::result<T>` instead of
`system::result<tuple<...>>`.
@par Example
Rules are used with the function @ref parse.
@code
system::result< std::tuple< unsigned char, unsigned char, unsigned char, unsigned char > > rv =
parse( "192.168.0.1",
tuple_rule(
dec_octet_rule,
squelch( delim_rule('.') ),
dec_octet_rule,
squelch( delim_rule('.') ),
dec_octet_rule,
squelch( delim_rule('.') ),
dec_octet_rule ) );
@endcode
@par BNF
@code
sequence = rule1 rule2 rule3...
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.1"
>3.1. Concatenation (rfc5234)</a>
@param rn A list of one or more rules to match
@see
@ref dec_octet_rule,
@ref delim_rule,
@ref parse,
@ref squelch.
*/
#ifdef BOOST_URL_DOCS
template<class... Rules>
constexpr
__implementation_defined__
tuple_rule( Rules... rn ) noexcept;
#else
template<
class R0,
class... Rn>
class tuple_rule_t
: empty_value<
detail::tuple<R0, Rn...>>
{
using T = mp11::mp_remove<
std::tuple<
typename R0::value_type,
typename Rn::value_type...>,
void>;
static constexpr bool IsList =
mp11::mp_size<T>::value != 1;
public:
using value_type =
mp11::mp_eval_if_c<IsList,
T, mp11::mp_first, T>;
template<
class R0_,
class... Rn_>
friend
constexpr
auto
tuple_rule(
R0_ const& r0,
Rn_ const&... rn) noexcept ->
tuple_rule_t<R0_, Rn_...>;
system::result<value_type>
parse(
char const*& it,
char const* end) const;
private:
constexpr
tuple_rule_t(
R0 const& r0,
Rn const&... rn) noexcept
: empty_value<
detail::tuple<R0, Rn...>>(
empty_init,
r0, rn...)
{
}
};
template<
class R0,
class... Rn>
constexpr
auto
tuple_rule(
R0 const& r0,
Rn const&... rn) noexcept ->
tuple_rule_t<
R0, Rn...>
{
return { r0, rn... };
}
#endif
#ifndef BOOST_URL_DOCS
namespace detail {
template<class Rule>
struct squelch_rule_t
: empty_value<Rule>
{
using value_type = void;
constexpr
squelch_rule_t(
Rule const& r) noexcept
: empty_value<Rule>(
empty_init, r)
{
}
system::result<value_type>
parse(
char const*& it,
char const* end) const
{
auto rv = this->get().parse(it, end);
if(rv.error())
return rv.error();
return {}; // void
}
};
} // detail
#endif
/** Squelch the value of a rule
This function returns a new rule which
matches the specified rule, and converts
its value type to `void`. This is useful
for matching delimiters in a grammar,
where the value for the delimiter is not
needed.
@par Value Type
@code
using value_type = void;
@endcode
@par Example 1
With `squelch`:
@code
system::result< std::tuple< decode_view, core::string_view > > rv = parse(
"www.example.com:443",
tuple_rule(
pct_encoded_rule(unreserved_chars + '-' + '.'),
squelch( delim_rule( ':' ) ),
token_rule( digit_chars ) ) );
@endcode
@par Example 2
Without `squelch`:
@code
system::result< std::tuple< decode_view, core::string_view, core::string_view > > rv = parse(
"www.example.com:443",
tuple_rule(
pct_encoded_rule(unreserved_chars + '-' + '.'),
delim_rule( ':' ),
token_rule( digit_chars ) ) );
@endcode
@param r The rule to squelch
@see
@ref delim_rule,
@ref digit_chars,
@ref parse,
@ref tuple_rule,
@ref token_rule,
@ref decode_view,
@ref pct_encoded_rule,
@ref unreserved_chars.
*/
template<class Rule>
constexpr
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
detail::squelch_rule_t<Rule>
#endif
squelch( Rule const& r ) noexcept
{
return { r };
}
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/tuple_rule.hpp>
#endif

View File

@@ -0,0 +1,68 @@
//
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_TYPE_TRAITS_HPP
#define BOOST_URL_GRAMMAR_TYPE_TRAITS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
/** Determine if T meets the requirements of Rule
This is an alias for `std::true_type` if
`T` meets the requirements, otherwise it
is an alias for `std::false_type`.
@par Example
@code
struct U
{
struct value_type;
auto
parse(
char const*& it,
char const* end) const ->
system::result<value_type>
};
static_assert( is_rule<U>::value, "Requirements not met" );
@endcode
@see
@ref parse.
*/
#ifdef BOOST_URL_DOCS
template<class T>
using is_rule = __see_below__;
#else
template<class T, class = void>
struct is_rule : std::false_type {};
template<class T>
struct is_rule<T, void_t<decltype(
std::declval<system::result<typename T::value_type>&>() =
std::declval<T const&>().parse(
std::declval<char const*&>(),
std::declval<char const*>())
)>> : std::is_nothrow_copy_constructible<T>
{
};
#endif
} // grammar
} // urls
} // boost
#endif

View File

@@ -0,0 +1,82 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2022 Alan de Freitas (alandefreitas 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_UNSIGNED_RULE_HPP
#define BOOST_URL_GRAMMAR_UNSIGNED_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/grammar/charset.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/static_assert.hpp>
#include <limits>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
/** Match an unsigned decimal
Extra leading zeroes are disallowed.
@par Value Type
@code
using value_type = Unsigned;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
system::result< unsigned short > rv = parse( "32767", unsigned_rule< unsigned short >{} );
@endcode
@par BNF
@code
unsigned = "0" / ( ["1"..."9"] *DIGIT )
@endcode
@tparam Unsigned The unsigned integer type used
to store the result.
@see
@ref grammar::parse.
*/
#ifdef BOOST_URL_DOCS
template<class Unsigned>
struct unsigned_rule;
#else
template<class Unsigned>
struct unsigned_rule
{
BOOST_STATIC_ASSERT(
std::numeric_limits<
Unsigned>::is_integer &&
! std::numeric_limits<
Unsigned>::is_signed);
using value_type = Unsigned;
auto
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>;
};
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/unsigned_rule.hpp>
#endif

View File

@@ -0,0 +1,131 @@
//
// Copyright (c) 2016-2019 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_VARIANT_RULE_HPP
#define BOOST_URL_GRAMMAR_VARIANT_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/variant.hpp>
#include <boost/url/grammar/detail/tuple.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** Match one of a set of rules
Each specified rule is tried in sequence.
When the first match occurs, the result
is stored and returned in the variant. If
no match occurs, an error is returned.
@par Value Type
@code
using value_type = variant< typename Rules::value_type... >;
@endcode
@par Example
Rules are used with the function @ref parse.
@code
// request-target = origin-form
// / absolute-form
// / authority-form
// / asterisk-form
system::result< variant< url_view, url_view, authority_view, core::string_view > > rv = grammar::parse(
"/index.html?width=full",
variant_rule(
origin_form_rule,
absolute_uri_rule,
authority_rule,
delim_rule('*') ) );
@endcode
@par BNF
@code
variant = rule1 / rule2 / rule3...
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.2"
>3.2. Alternatives (rfc5234)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-5.3"
>5.3. Request Target (rfc7230)</a>
@see
@ref absolute_uri_rule,
@ref authority_rule,
@ref delim_rule,
@ref parse,
@ref origin_form_rule,
@ref url_view.
*/
#ifdef BOOST_URL_DOCS
template<class... Rules>
constexpr
__implementation_defined__
variant_rule( Rules... rn ) noexcept;
#else
template<
class R0, class... Rn>
class variant_rule_t
{
public:
using value_type = variant<
typename R0::value_type,
typename Rn::value_type...>;
auto
parse(
char const*& it,
char const* end) const ->
system::result<value_type>;
template<
class R0_,
class... Rn_>
friend
constexpr
auto
variant_rule(
R0_ const& r0,
Rn_ const&... rn) noexcept ->
variant_rule_t<R0_, Rn_...>;
private:
constexpr
variant_rule_t(
R0 const& r0,
Rn const&... rn) noexcept
: rn_(r0, rn...)
{
}
detail::tuple<R0, Rn...> rn_;
};
template<
class R0,
class... Rn>
constexpr
auto
variant_rule(
R0 const& r0,
Rn const&... rn) noexcept ->
variant_rule_t<R0, Rn...>;
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/variant_rule.hpp>
#endif

View File

@@ -0,0 +1,85 @@
//
// 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/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_VCHARS_HPP
#define BOOST_URL_GRAMMAR_VCHARS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/detail/charset.hpp>
namespace boost {
namespace urls {
namespace grammar {
/** The set of visible characters
@par Example
Character sets are used with rules and the
functions @ref find_if and @ref find_if_not.
@code
system::result< core::string_view > rv = parse( "JohnDoe", token_rule( vchars ) );
@endcode
@par BNF
@code
VCHAR = 0x21-0x7E
; visible (printing) characters
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
>B.1. Core Rules (rfc5234)</a>
@see
@ref find_if,
@ref find_if_not,
@ref parse,
@ref token_rule.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ vchars;
#else
struct vchars_t
{
constexpr
bool
operator()(char c) const noexcept
{
return c >= 0x21 && c <= 0x7e;
}
#ifdef BOOST_URL_USE_SSE2
char const*
find_if(
char const* first,
char const* last) const noexcept
{
return detail::find_if_pred(
*this, first, last);
}
char const*
find_if_not(
char const* first,
char const* last) const noexcept
{
return detail::find_if_not_pred(
*this, first, last);
}
#endif
};
constexpr vchars_t vchars{};
#endif
} // grammar
} // urls
} // boost
#endif